From 9f47254090f18055905a35cd4bdf6f62f0daf0d6 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 18 Oct 2020 18:46:36 +0200 Subject: [PATCH] Degenerated Trie Test Tests for a ByteTrie that degenerates to a doubly linked list --- README.md | 4 ++- tests/conftest.py | 3 +- tests/test_bytetrie_blackbox.py | 18 ++++++++++- tests/tries/degenerated_trie.png | Bin 0 -> 53563 bytes tests/tries/degenerated_trie.py | 51 +++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 tests/tries/degenerated_trie.png create mode 100644 tests/tries/degenerated_trie.py diff --git a/README.md b/README.md index 54d0893..28ae78c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ # Bytetrie A fast, dependency-free, self-compressing trie with radix 256 in pure python. -![](trie.png) +| ![Artistic ByteTrie Render](trie.png) | +|--------------------------------------------------------------------------------------------------------------------------:| +| *Rendering of a ByteTrie containing [~200,000 cities with a population > 500](http://download.geonames.org/export/dump/)* | Bytetrie allows fast prefix search in a large corpus of keys. Each key can be associated with arbitrary data. It features fast lookup times at the cost of diff --git a/tests/conftest.py b/tests/conftest.py index aae94a5..1ab91a9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ import pytest pytest_plugins = [ - "tries.simple_trie" + "tries.simple_trie", + "tries.degenerated_trie" ] diff --git a/tests/test_bytetrie_blackbox.py b/tests/test_bytetrie_blackbox.py index 19f84a8..3227aa7 100644 --- a/tests/test_bytetrie_blackbox.py +++ b/tests/test_bytetrie_blackbox.py @@ -2,11 +2,12 @@ import pytest import sys import os -sys.path.append("tests/tries/") from bytetrie import ByteTrie +sys.path.append("tests/tries/") import simple_trie +import degenerated_trie def test_find_all(simple_trie): r = simple_trie.find(b"A") @@ -47,3 +48,18 @@ def test_partial_prefix_find_terminal(simple_trie): assert len(r) == 1 assert r[0].key() == b"ABCDE" assert r[0].value() == "ABCDE" + +def test_degenerated_find_first_finds_all(degenerated_trie): + r = degenerated_trie.find(b"A") + assert len(r) == 26 + assert r[0].key() == b"A" + assert r[0].value() == "A" + + assert r[25].key() == b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + assert r[25].value() == "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +def test_degenerated_find_last_finds_one(degenerated_trie): + r = degenerated_trie.find(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ") + assert len(r) == 1 + assert r[0].key() == b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + assert r[0].value() == "ABCDEFGHIJKLMNOPQRSTUVWXYZ" diff --git a/tests/tries/degenerated_trie.png b/tests/tries/degenerated_trie.png new file mode 100644 index 0000000000000000000000000000000000000000..0d45684f484b6ff76d25f2745b8f860653749342 GIT binary patch literal 53563 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 literal 0 HcmV?d00001 diff --git a/tests/tries/degenerated_trie.py b/tests/tries/degenerated_trie.py new file mode 100644 index 0000000..c93901f --- /dev/null +++ b/tests/tries/degenerated_trie.py @@ -0,0 +1,51 @@ +""" +A degenerated ByteTrie fixture. ByteTrie resolves to a doubly-linked list. The +worst case scenario. + +See degenerated_trie.png +""" + +import pytest + +from bytetrie import ByteTrie + +def insert(trie): + """ Shall only be used to insert strings """ + t = trie + def _insert(*vals): + for val in vals: + t.insert(val.encode('utf-8'), val) + return _insert + +@pytest.fixture +def degenerated_trie(): + t = ByteTrie() + ins = insert(t) + ins("A") + ins("AB") + ins("ABC") + ins("ABCD") + ins("ABCDE") + ins("ABCDEF") + ins("ABCDEFG") + ins("ABCDEFGH") + ins("ABCDEFGHI") + ins("ABCDEFGHIJ") + ins("ABCDEFGHIJK") + ins("ABCDEFGHIJKL") + ins("ABCDEFGHIJKLM") + ins("ABCDEFGHIJKLMN") + ins("ABCDEFGHIJKLMNO") + ins("ABCDEFGHIJKLMNOP") + ins("ABCDEFGHIJKLMNOPQ") + ins("ABCDEFGHIJKLMNOPQR") + ins("ABCDEFGHIJKLMNOPQRS") + ins("ABCDEFGHIJKLMNOPQRST") + ins("ABCDEFGHIJKLMNOPQRSTU") + ins("ABCDEFGHIJKLMNOPQRSTUV") + ins("ABCDEFGHIJKLMNOPQRSTUVW") + ins("ABCDEFGHIJKLMNOPQRSTUVWX") + ins("ABCDEFGHIJKLMNOPQRSTUVWXY") + ins("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + + return t