예제 #1
0
        public CommandHandler(ArisaTwitchClient arisaTwitchClient)
        {
            ArisaTwitchClient = arisaTwitchClient;
            _commandTree      = new CompactPrefixTree <ICommand>(16, 32, 32);

            Add(new CommandListCommand(this));
        }
예제 #2
0
        static CompactPrefixTreeVersusDictionary()
        {
            string wordsPath = @"C:\MihaZupan\SharpCollections\test\Benchmark\words.txt";

            Words = File.ReadAllLines(wordsPath);
            for (int i = 0; i < 5; i++)
            {
                Words.Shuffle(12345 + i);
            }

            int count = 0;

            Pairs = Words.Select(w => new KeyValuePair <string, int>(w, w.Length)).ToArray();
            Pairs = Pairs.Where(_ => ++ count % 1000 == 0).ToArray();

            PrefixTree            = new CompactPrefixTree <int>(Pairs, ignoreCase: false);
            PrefixTree_IgnoreCase = new CompactPrefixTree <int>(Pairs, ignoreCase: true);
            Dictionary_Ordinal    = new Dictionary <string, int>(Pairs, StringComparer.Ordinal);
            Dictionary_IgnoreCase = new Dictionary <string, int>(Pairs, StringComparer.OrdinalIgnoreCase);

            for (int i = 0; i < 5; i++)
            {
                Words.Shuffle(12345 + i);
            }
        }
예제 #3
0
        public void MimicsDictionaryExceptionsBehavior()
        {
            Dictionary <string, int> dictionary = new Dictionary <string, int>();
            CompactPrefixTree <int>  tree       = new CompactPrefixTree <int>();

            Assert.Throws <KeyNotFoundException>(() => { int num = tree["foo"]; });
            Assert.Throws <KeyNotFoundException>(() => { int num = dictionary["foo"]; });

            tree["foo"] = 1;
            Assert.Equal(1, tree["foo"]);

            dictionary["foo"] = 1;
            Assert.Equal(1, dictionary["foo"]);

            tree["foo"] = 2;
            Assert.Equal(2, tree["foo"]);

            dictionary["foo"] = 2;
            Assert.Equal(2, dictionary["foo"]);

            Assert.Throws <ArgumentException>(() => { tree.Add("foo", 1); });
            Assert.Equal(2, tree["foo"]);

            Assert.Throws <ArgumentException>(() => { dictionary.Add("foo", 1); });
            Assert.Equal(2, dictionary["foo"]);
        }
예제 #4
0
        public void SetsCorrectCapacity()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>();

            Assert.Equal(0, tree.Capacity);
            Assert.Equal(0, tree.TreeCapacity);

            tree = new CompactPrefixTree <int>
            {
                { "foo", 1 }, { "foo bar", 2 }, { "bar", 3 }, { "Bar", 4 }, { "foobar", 5 }
            };
            Assert.Equal(5, tree.Count);
            Assert.Equal(8, tree.Capacity);      // Grows by powers of 2
            Assert.Equal(7, tree.TreeSize);      // 'f', 'fo', 'foo', 'foo bar', 'foobar', 'bar', 'Bar'
            Assert.Equal(12, tree.TreeCapacity); // 1, 3, 6, 12
            // 1 => 3 happens because internally when adding "foo bar", we call Ensure(1 + 2) to accomodate two leaf nodes
            // After that the capacity is doubled
            Assert.Equal(2, tree.ChildrenCount); // only "foo bar" and "foobar" will force a child (ChildrenCount is double the amount of actual children entries)
            Assert.Equal(2, tree.ChildrenCapacity);

            tree = new CompactPrefixTree <int>(new[]
            {
                new KeyValuePair <string, int>("foo", 1),
                new KeyValuePair <string, int>("foo bar", 2),
                new KeyValuePair <string, int>("bar", 3),
                new KeyValuePair <string, int>("Bar", 4),
                new KeyValuePair <string, int>("foobar", 5)
            });
            Assert.Equal(5, tree.Count);
            Assert.Equal(5, tree.Capacity);          // Set correctly since it was known at construction-time
            Assert.Equal(7, tree.TreeSize);
            Assert.Equal(10, tree.TreeCapacity);     // Set to 2 * input.Count in the constructor
            Assert.Equal(2, tree.ChildrenCount);
            Assert.Equal(10, tree.ChildrenCapacity); // Initially set to 2 * input.Count
        }
예제 #5
0
        public void DoesOrdinalComparrison()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "Hello", 1 }
            };

            Assert.Equal(1, tree["Hello"]);
            Assert.Throws <KeyNotFoundException>(() => { int num = tree["hello"]; });
        }
예제 #6
0
        public void AcceptsSpans()
        {
#if NETCORE
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "Hell", 1 },
                { "Hello", 2 },
                { "Hello world", 3 },
                { "Hello world!", 4 },
                { "wor", 5 },
                { "world", 6 },
                { " ", 7 }
            };

            //             0         1
            //             012345678901
            string text = "Hello world!";

            Assert.False(tree.TryMatchExact(text.AsSpan(0, 3), out var match));

            Assert.True(tree.TryMatchExact(text.AsSpan(0, 4), out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchExact(text.AsSpan(0, 5), out match));
            Assert.Equal("Hello", match.Key);
            Assert.True(tree.TryMatchShortest(text.AsSpan(5, 5), out match));
            Assert.Equal(" ", match.Key);
            Assert.True(tree.TryMatchShortest(text.AsSpan(0, 5), out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(0, 5), out match));
            Assert.Equal("Hello", match.Key);
            Assert.True(tree.TryMatchShortest(text, out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(6), out match));
            Assert.Equal("world", match.Key);
            Assert.True(tree.TryMatchShortest(text.AsSpan(6), out match));
            Assert.Equal("wor", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(6, 4), out match));
            Assert.Equal("wor", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(), out match));
            Assert.Equal("Hello world!", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(0, text.Length - 1), out match));
            Assert.Equal("Hello world", match.Key);
            Assert.True(tree.TryMatchLongest(text.AsSpan(0, text.Length - 2), out match));
            Assert.Equal("Hello", match.Key);

            Assert.False(tree.TryMatchExact(text.AsSpan(6), out match));
            Assert.Throws <KeyNotFoundException>(() => { match = tree[text.AsSpan(6)]; });
            tree.Add("world!", 7);
            Assert.True(tree.TryMatchExact(text.AsSpan(6), out match));
            Assert.Equal("world!", match.Key);
            match = tree[text.AsSpan(6)];
            Assert.Equal("world!", match.Key);
#endif
        }
예제 #7
0
        public void ModifiesValue()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "Hello", 1 }
            };

            Assert.Equal(1, tree["Hello"]);

            tree["Hello"] = 2;
            Assert.Equal(2, tree["Hello"]);
        }
        public void PrexiTree_Find_NonExistant()
        {
            var tree = new CompactPrefixTree();

            tree.Add("test$", 1);
            tree.Add("testing$", 2);
            tree.Add("example$", 3);
            tree.Add("examples$", 4);

            var result = tree.FindIdsWithPrefix("hello");

            Assert.AreEqual(0, result.Count);
        }
예제 #9
0
        public void SupportsUnicode()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "ümlaüt", 12345 }
            };

            Assert.False(tree.ContainsKey("umlaüt"));
            Assert.True(tree.ContainsKey("ümlaüt"));
            Assert.False(tree.ContainsKey("Ümlaüt"));

            // We don't support Right-To-Left, don't push it
        }
        public void PrexiTree_Find_Exact()
        {
            var tree = new CompactPrefixTree();

            tree.Add("test$", 1);
            tree.Add("testing$", 2);
            tree.Add("example$", 3);
            tree.Add("examples$", 4);

            var result = tree.FindIdsWithPrefix("example$");

            Assert.AreEqual(1, result.Count);
            Assert.AreEqual(3, result[0].PostingListId);
        }
예제 #11
0
        public void AcceptsSubstrings()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "Hell", 1 },
                { "Hello", 2 },
                { "Hello world", 3 },
                { "Hello world!", 4 },
                { "wor", 5 },
                { "world", 6 },
                { " ", 7 }
            };

            //             0         1
            //             012345678901
            string text = "Hello world!";

            Assert.False(tree.TryMatchExact(text, 0, 3, out var match));

            Assert.True(tree.TryMatchExact(text, 0, 4, out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchExact(text, 0, 5, out match));
            Assert.Equal("Hello", match.Key);
            Assert.True(tree.TryMatchShortest(text, 5, 5, out match));
            Assert.Equal(" ", match.Key);
            Assert.True(tree.TryMatchShortest(text, 0, 5, out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchLongest(text, 0, 5, out match));
            Assert.Equal("Hello", match.Key);
            Assert.True(tree.TryMatchShortest(text, out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchLongest(text, 6, out match));
            Assert.Equal("world", match.Key);
            Assert.True(tree.TryMatchShortest(text, 6, out match));
            Assert.Equal("wor", match.Key);
            Assert.True(tree.TryMatchLongest(text, 6, 4, out match));
            Assert.Equal("wor", match.Key);
            Assert.True(tree.TryMatchLongest(text, 0, text.Length, out match));
            Assert.Equal("Hello world!", match.Key);
            Assert.True(tree.TryMatchLongest(text, 0, text.Length - 1, out match));
            Assert.Equal("Hello world", match.Key);
            Assert.True(tree.TryMatchLongest(text, 0, text.Length - 2, out match));
            Assert.Equal("Hello", match.Key);

            Assert.False(tree.TryMatchExact(text, 6, out match));
            tree.Add("world!", 7);
            Assert.True(tree.TryMatchExact(text, 6, out match));
            Assert.Equal("world!", match.Key);
        }
        public void PrexiTree_Find_CorrectTerms()
        {
            var tree = new CompactPrefixTree();

            tree.Add("test$", 1);
            tree.Add("testing$", 2);
            tree.Add("tesserect$", 5);
            tree.Add("example$", 3);
            tree.Add("examples$", 4);

            var result = tree.FindIdsWithPrefix("test");

            Assert.AreEqual(2, result.Count);
            Assert.AreEqual("test$", result[0].Term);
            Assert.AreEqual("testing$", result[1].Term);
        }
예제 #13
0
        public void ImplementsInterfaces()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "Hello", 1 },
                { "World", 2 }
            };

            var dictionary = tree as IReadOnlyDictionary <string, int>;
            var list       = tree as IReadOnlyList <KeyValuePair <string, int> >;

            Assert.NotNull(dictionary);
            Assert.NotNull(list);

            Assert.Equal(dictionary.Keys, new[] { "Hello", "World" });
            Assert.Equal(dictionary.Values, new[] { 1, 2 });

            Assert.True(dictionary.ContainsKey("Hello"));
            Assert.False(dictionary.ContainsKey("Foo"));

            Assert.True(dictionary.TryGetValue("Hello", out int value));
            Assert.Equal(1, value);

            Assert.Equal(list.Count, dictionary.Count);
            Assert.Equal(new KeyValuePair <string, int>("Hello", 1), list[0]);
            Assert.Equal(new KeyValuePair <string, int>("World", 2), list[1]);

            Assert.Equal(list, new[] { new KeyValuePair <string, int>("Hello", 1), new KeyValuePair <string, int>("World", 2) });
            Assert.Equal(dictionary.ToDictionary(p => p.Key, p => p.Value), new Dictionary <string, int>()
            {
                { "Hello", 1 }, { "World", 2 }
            });

            using (var e = tree.GetEnumerator())
            {
                Assert.True(e.MoveNext());
                Assert.Equal(1, e.Current.Value);
                Assert.True(e.MoveNext());
                Assert.Equal(2, e.Current.Value);
                Assert.False(e.MoveNext());
                Assert.Throws <IndexOutOfRangeException>(() => { var element = e.Current; });
                e.Reset();
                Assert.True(e.MoveNext());
                Assert.Equal(1, e.Current.Value);
            }
        }
예제 #14
0
        public void MatchesExact()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>
            {
                { "foo", 1 }, { "foo bar", 2 }
            };

            Assert.True(tree.TryMatchExact("foo bar", out KeyValuePair <string, int> match));
            Assert.Equal(match, new KeyValuePair <string, int>("foo bar", 2));

            Assert.False(tree.TryMatchExact("foo ba", out match));

            Assert.True(tree.TryMatchExact("foo", out match));
            Assert.Equal(match, new KeyValuePair <string, int>("foo", 1));

            Assert.False(tree.TryMatchExact("fo", out match));
        }
예제 #15
0
        public void SupportsCaseInsensitivity()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>(ignoreCase: true)
            {
                { "Hell", 1 },
                { "Hello", 2 },
                { "Hello world", 3 },
                { "Hello world!", 4 },
                { "wor", 5 },
                { "world", 6 },
                { " ", 7 }
            };

            //             0         1
            //             012345678901
            string text = "HeLLo woRld!";

            Assert.True(tree.TryMatchLongest(text, out var match));
            Assert.Equal("Hello world!", match.Key);
            Assert.True(tree.TryMatchLongest(text, 6, out match));
            Assert.Equal("world", match.Key);
            Assert.True(tree.ContainsKey("hello"));
            int value = tree["wOr"];

            Assert.Equal(5, value);

#if NETCORE
            Assert.False(tree.TryMatchExact(text.AsSpan(0, 3), out match));

            Assert.True(tree.TryMatchExact(text.AsSpan(0, 4), out match));
            Assert.Equal("Hell", match.Key);
            Assert.True(tree.TryMatchExact(text.AsSpan(0, 5), out match));
            Assert.Equal("Hello", match.Key);

            Assert.False(tree.TryMatchExact(text.AsSpan(6), out match));
            Assert.Throws <KeyNotFoundException>(() => { match = tree[text.AsSpan(6)]; });
            tree.Add("world!", 7);
            Assert.True(tree.TryMatchExact(text.AsSpan(6), out match));
            Assert.Equal("world!", match.Key);
            match = tree[text.AsSpan(6)];
            Assert.Equal("world!", match.Key);
#endif
        }
예제 #16
0
        public void ExampleTest()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>(ignoreCase: false)
            {
                { "Hell", 1 },
                { "Hello", 2 },
                { "Hello world", 3 },
                { "Hello world!", 4 },
                { "world", 5 }
            };

            if (tree.TryMatchLongest("Hello everyone!", out KeyValuePair <string, int> match))
            {
                Console.WriteLine("Matched {0}: {1}", match.Key, match.Value); // Hello, 2
            }
            if (tree.TryMatchExact("Hello ", out match))
            {
                Console.WriteLine("This is not gonna happen");
            }

            if (tree.TryMatchLongest("Hello ", out match))
            {
                Console.WriteLine("But this will: " + match.Key); // Hello
            }
            if (tree.TryMatchShortest("Hello ", out match))
            {
                Console.WriteLine("So will this: " + match.Key); // Hell
            }
            // You can read/set/add values the same way you would in a dictionary
            tree["world"]        = 123;
            tree["second world"] = 321;
            Console.WriteLine(tree["world"]);

            // Or add them explicitly
            tree.Add("Foo", 1);    // Will throw if already present
            tree.TryAdd("Bar", 2); // Will return false if already present

            // You can access key/value pairs by index
            match = tree[3]; // Hello world!, 4

            // Only downside of this data structure is not being able to remove elements
            // tree.Remove("key");
        }
예제 #17
0
        public void ValidatesInput()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>();

            Assert.Throws <ArgumentNullException>(() => { new CompactPrefixTree <int>(null); });

            Assert.Throws <ArgumentNullException>(() => { tree[null] = 123; });
            Assert.Throws <ArgumentNullException>(() => { int num = tree[null]; });
            Assert.Throws <ArgumentNullException>(() => { tree.Add(null, 123); });
            Assert.Throws <ArgumentNullException>(() => { tree.TryAdd(null, 123); });
            Assert.Throws <ArgumentNullException>(() => { tree.TryMatchShortest(null, out _); });
            Assert.Throws <ArgumentNullException>(() => { tree.TryMatchExact(null, out _); });
            Assert.Throws <ArgumentNullException>(() => { tree.TryMatchLongest(null, out _); });
            Assert.Throws <ArgumentNullException>(() => { tree.TryGetValue(null, out _); });
            Assert.Throws <ArgumentNullException>(() => { tree.ContainsKey(null); });

            Assert.Throws <ArgumentOutOfRangeException>(() => { tree[""] = 123; });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.Add("", 123); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryAdd("", 123); });

            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchShortest("Foo", -1, 0, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchShortest("Foo", 0, -1, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchShortest("Foo", 3, 3, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchExact("Foo", -1, 0, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchExact("Foo", 0, -1, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchExact("Foo", 3, 3, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchLongest("Foo", -1, 0, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchLongest("Foo", 0, -1, out _); });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TryMatchLongest("Foo", 3, 3, out _); });

            Assert.Throws <IndexOutOfRangeException>(() => { var match = tree[-1]; });
            Assert.Throws <IndexOutOfRangeException>(() => { var match = tree[5]; });

            tree.Capacity     = 0;
            tree.TreeCapacity = 0;
            tree.Add("Hello", 123);
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.Capacity = 0; });
            Assert.Throws <ArgumentOutOfRangeException>(() => { tree.TreeCapacity = 0; });
        }
예제 #18
0
        private void DocumentOnProcessInlinesBegin(InlineProcessor inlineProcessor, Inline inline)
        {
            inlineProcessor.Document.ProcessInlinesBegin -= DocumentOnProcessInlinesBegin;

            var abbreviations = inlineProcessor.Document.GetAbbreviations();

            // Should not happen, but another extension could decide to remove them, so...
            if (abbreviations == null)
            {
                return;
            }

            // Build a text matcher from the abbreviations labels
            var prefixTree = new CompactPrefixTree <Abbreviation>(abbreviations);

            inlineProcessor.LiteralInlineParser.PostMatch += (InlineProcessor processor, ref StringSlice slice) =>
            {
                var literal         = (LiteralInline)processor.Inline;
                var originalLiteral = literal;

                ContainerInline container = null;

                // This is slow, but we don't have much the choice
                var content = literal.Content;
                var text    = content.Text;

                for (int i = content.Start; i <= content.End; i++)
                {
                    // Abbreviation must be a whole word == start at the start of a line or after a whitespace
                    if (i != 0)
                    {
                        for (i = i - 1; i <= content.End; i++)
                        {
                            if (text[i].IsWhitespace())
                            {
                                i++;
                                goto ValidAbbreviationStart;
                            }
                        }
                        break;
                    }

                    ValidAbbreviationStart :;

                    if (prefixTree.TryMatchLongest(text, i, content.End - i + 1, out KeyValuePair <string, Abbreviation> abbreviationMatch))
                    {
                        var match = abbreviationMatch.Key;
                        if (!IsValidAbbreviationEnding(match, content, i))
                        {
                            continue;
                        }

                        var indexAfterMatch = i + match.Length;

                        // If we don't have a container, create a new one
                        if (container == null)
                        {
                            container = literal.Parent ??
                                        new ContainerInline
                            {
                                Span   = originalLiteral.Span,
                                Line   = originalLiteral.Line,
                                Column = originalLiteral.Column,
                            };
                        }

                        var abbrInline = new AbbreviationInline(abbreviationMatch.Value)
                        {
                            Span =
                            {
                                Start = processor.GetSourcePosition(i, out int line, out int column),
                            },
                            Line   = line,
                            Column = column
                        };
                        abbrInline.Span.End = abbrInline.Span.Start + match.Length - 1;

                        // Append the previous literal
                        if (i > content.Start && literal.Parent == null)
                        {
                            container.AppendChild(literal);
                        }

                        literal.Span.End = abbrInline.Span.Start - 1;
                        // Truncate it before the abbreviation
                        literal.Content.End = i - 1;


                        // Append the abbreviation
                        container.AppendChild(abbrInline);

                        // If this is the end of the string, clear the literal and exit
                        if (content.End == indexAfterMatch - 1)
                        {
                            literal = null;
                            break;
                        }

                        // Process the remaining literal
                        literal = new LiteralInline()
                        {
                            Span   = new SourceSpan(abbrInline.Span.End + 1, literal.Span.End),
                            Line   = line,
                            Column = column + match.Length,
                        };
                        content.Start   = indexAfterMatch;
                        literal.Content = content;

                        i = indexAfterMatch - 1;
                    }
예제 #19
0
 public override void Initialize()
 {
     OpeningCharacters = EnableSmiley ? EmojiSmileyOpeningCharactersDefault : EmojiOpeningCharactersDefault;
     _emojiPrefixTree  = EnableSmiley ? EmojiSmileyPrefixTreeDefault : EmojiPrefixTreeDefault;
 }
예제 #20
0
        public void UsesAllRelevantCodePaths()
        {
            CompactPrefixTree <int> tree = new CompactPrefixTree <int>()
            {
                { "A", 1 }, { "Abc", 2 }, { "Aeiou", 3 },
                { "fooob", 4 }, { "foobar1", 5 }, { "foobar2", 6 }
            };

            Assert.False(tree.ContainsKey("a"));
            Assert.True(tree.ContainsKey("A"));
            Assert.False(tree.TryGetValue("a", out _));
            Assert.True(tree.TryGetValue("A", out _));
            Assert.False(tree.TryMatchShortest("a", out _));
            Assert.True(tree.TryMatchShortest("A", out _));
            Assert.False(tree.TryMatchExact("a", out _));
            Assert.True(tree.TryMatchExact("A", out _));
            Assert.False(tree.TryMatchLongest("a", out _));
            Assert.True(tree.TryMatchLongest("A", out _));

            Assert.True(tree.TryMatchLongest("Aeiou and something", out KeyValuePair <string, int> match));
            Assert.Equal(3, match.Value);

            Assert.True(tree.TryMatchExact("Abc", out match));
            Assert.Equal(2, match.Value);

            Assert.True(tree.TryMatchShortest("Aeiou and something", out match));
            Assert.Equal("A", match.Key);
            Assert.Equal(1, match.Value);

            Assert.True(tree.TryMatchLongest("foobar123", out match));
            Assert.Equal("foobar1", match.Key);
            Assert.Equal(5, match.Value);

            Assert.False(tree.TryMatchExact("foobar123", out match));

            Assert.True(tree.TryMatchShortest("foobar123", out match));
            Assert.Equal("foobar1", match.Key);
            Assert.Equal(5, match.Value);

            tree.Add("full", 10);

            Assert.True(tree.TryMatchLongest("fullbar123", out match));
            Assert.Equal("full", match.Key);
            Assert.Equal(10, match.Value);

            Assert.False(tree.TryMatchExact("fullbar123", out match));

            Assert.True(tree.TryMatchShortest("fullbar123", out match));
            Assert.Equal("full", match.Key);
            Assert.Equal(10, match.Value);

            tree.Add(new KeyValuePair <string, int>("Hello", 321));
            Assert.True(tree.ContainsKey("Hello"));
            tree.TryAdd(new KeyValuePair <string, int>("Hello", 123));
            Assert.Equal(321, tree["Hello"]);

            tree.Add("Hell", 123);
            Assert.Equal(321, tree["Hello"]);
            Assert.Equal(123, tree["Hell"]);

            tree.Add("aa", 2);
            tree.Add("ab", 3);
            tree.Add("ac", 4);
            tree.Add("ad", 5);
            tree.Add("ae", 6);

            Assert.False(tree.TryMatchLongest("af", out match));
            Assert.False(tree.TryMatchShortest("af", out match));

            Assert.Equal(5, tree["ad"]);
            Assert.Equal(6, tree["ae"]);

            tree.TryAdd("af", 7);
            Assert.Equal(7, tree["af"]);

            Assert.False(tree.ContainsKey("ag"));

            Assert.False(tree.TryAdd("A", 2));

            tree.Add("something", 123);
            tree.Add("soms", 789);
            tree.Add("some", 456);

            Assert.False(tree.ContainsKey("son"));
            Assert.True(tree.ContainsKey("soms"));
        }