Skip to content
This repository was archived by the owner on Mar 9, 2026. It is now read-only.

Commit ecf81c1

Browse files
committed
Create basic tests covering excavation & output generation for example.
Make the minimal set of changes such that we are able to trigger the excavation to a known directory of the in-tree example file. Check that the expected HTML files were written for this known excavation and assert some basic properties of the excavated arifacts. The commit includes reworking of run_example wherein its excavation is declared as a class and its core logic separated out into a run file. This is done both to allow the tests to easily make use of the logic and as groundwork for subsequent work to provide a unified entry point.
1 parent e46910b commit ecf81c1

File tree

5 files changed

+172
-25
lines changed

5 files changed

+172
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ docs/_build/
99
# Temporary files
1010
_.*
1111
_autoarchaologist/
12+
tests/_scratch/

run.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import argparse
2+
import os
3+
import sys
4+
5+
from autoarchaeologist.base.excavation import Excavation as ExcavationBase
6+
7+
def parse_arguments(argv=None):
8+
parser = argparse.ArgumentParser()
9+
parser.add_argument("-d", "--dir", default="/tmp/_autoarchaologist")
10+
parser.add_argument('filename')
11+
12+
return parser.parse_args(args=argv)
13+
14+
def process_arguments(args):
15+
if args.dir == ".":
16+
args.dir = os.path.join(os.getcwd(), "_autoarchaologist")
17+
if args.filename is not None:
18+
args.filename = os.path.abspath(args.filename)
19+
else:
20+
raise ValueError()
21+
22+
return args
23+
24+
def perform_excavation(args, action_tuple):
25+
match action_tuple:
26+
case "excavator", Excavation:
27+
assert issubclass(Excavation, ExcavationBase)
28+
ctx = Excavation(html_dir=args.dir)
29+
case action, _:
30+
raise NotImplementedError(f"action: {action}")
31+
32+
ff = ctx.add_file_artifact(args.filename)
33+
34+
ctx.start_examination()
35+
36+
return ctx
37+
38+
if __name__ == "__main__":
39+
args = process_arguments(parse_arguments())
40+
41+
try:
42+
os.mkdir(args.dir)
43+
except FileExistsError:
44+
pass
45+
46+
ctx = perform_excavation(args, ("none", None))
47+
ctx.produce_html()
48+
print("Now point your browser at", ctx.filename_for(ctx).link)

run_example.py

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
1-
2-
import argparse
31
import os
4-
import sys
5-
6-
import autoarchaeologist
2+
from run import process_arguments, perform_excavation
3+
from types import SimpleNamespace
74

5+
from autoarchaeologist.base.excavation import Excavation
86
from autoarchaeologist.generic.bigdigits import BigDigits
97
from autoarchaeologist.generic.samesame import SameSame
108
from autoarchaeologist.data_general.absbin import AbsBin
119
from autoarchaeologist.data_general.papertapechecksum import DGC_PaperTapeCheckSum
1210

13-
def parse_arguments(argv=None):
14-
parser = argparse.ArgumentParser()
15-
parser.add_argument("-d", "--dir", default="/tmp/_autoarchaologist")
11+
EXAMPLES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "examples")
1612

17-
args = parser.parse_args(args=argv)
18-
if args.dir == ".":
19-
args.dir = os.path.join(os.getcwd(), "_autoarchaologist")
20-
return args
13+
class ExampleExcavation(Excavation):
14+
def __init__(self, **kwargs):
15+
super().__init__(**kwargs)
2116

22-
if __name__ == "__main__":
23-
args = parse_arguments()
17+
self.add_examiner(BigDigits)
18+
self.add_examiner(AbsBin)
19+
self.add_examiner(DGC_PaperTapeCheckSum)
20+
self.add_examiner(SameSame)
21+
22+
def process_example(*, html_dir):
23+
example_arguments = SimpleNamespace()
24+
example_arguments.dir = html_dir
25+
example_arguments.filename = os.path.join(EXAMPLES_DIR, "30001393.bin")
26+
args = process_arguments(example_arguments)
2427

2528
try:
2629
os.mkdir(args.dir)
2730
except FileExistsError:
2831
pass
2932

30-
ctx = autoarchaeologist.Excavation(html_dir=args.dir)
31-
32-
ctx.add_examiner(BigDigits)
33-
ctx.add_examiner(AbsBin)
34-
ctx.add_examiner(DGC_PaperTapeCheckSum)
35-
ctx.add_examiner(SameSame)
36-
37-
ff = ctx.add_file_artifact("examples/30001393.bin")
38-
39-
ctx.start_examination()
33+
return perform_excavation(args, ("excavator", ExampleExcavation))
4034

35+
if __name__ == "__main__":
36+
ctx = process_example(html_dir=".")
4137
ctx.produce_html()
42-
4338
print("Now point your browser at", ctx.filename_for(ctx).link)

tests/__init__.py

Whitespace-only changes.

tests/test_run_example.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import importlib
2+
import os
3+
import shutil
4+
import sys
5+
import unittest
6+
7+
TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
8+
ROOT_DIR = os.path.normpath(os.path.join(TESTS_DIR, ".."))
9+
10+
# run_example is technically outside the package so force its import
11+
sys.path.append(ROOT_DIR)
12+
from run_example import process_example
13+
from autoarchaeologist.base.artifact import ArtifactBase, ArtifactStream
14+
sys.path.remove(ROOT_DIR)
15+
16+
SCRATCH_DIR = os.path.join(TESTS_DIR, "_scratch")
17+
18+
def scratch_path(path):
19+
return os.path.join(SCRATCH_DIR, path)
20+
21+
class RunExampleBasicHtml(unittest.TestCase):
22+
"""
23+
Ensure run_example produces expected HTML files for the example input.
24+
"""
25+
26+
DIR_TREE = None
27+
28+
@classmethod
29+
def setUpClass(cls):
30+
shutil.rmtree(SCRATCH_DIR)
31+
os.makedirs(SCRATCH_DIR, exist_ok=True)
32+
ctx = process_example(html_dir=SCRATCH_DIR)
33+
ctx.produce_html()
34+
cls.DIR_TREE = list(os.walk(SCRATCH_DIR))
35+
36+
def toplevel(self):
37+
return self.__class__.DIR_TREE[0]
38+
39+
def toplevel_dirnames(self):
40+
_, dirs, __ = self.toplevel()
41+
dirs.sort()
42+
return dirs
43+
44+
def toplevel_filenames(self):
45+
_, __, filenames = self.toplevel()
46+
return filenames
47+
48+
def test_produces_top_level_index(self):
49+
toplevel_filenames = self.toplevel_filenames()
50+
self.assertTrue("index.html" in toplevel_filenames)
51+
self.assertTrue("index.css" in toplevel_filenames)
52+
53+
def test_produces_digest_directories(self):
54+
toplevel_dirnames = self.toplevel_dirnames()
55+
self.assertEqual(toplevel_dirnames, ['08', '79', 'fa'])
56+
57+
class RunExampleBasicArtifacts(unittest.TestCase):
58+
"""
59+
Ensure run_example excavates the expected artifacts for the example input.
60+
"""
61+
62+
CTX = None
63+
64+
@classmethod
65+
def setUpClass(cls):
66+
cls.CTX = process_example(html_dir=SCRATCH_DIR)
67+
68+
def assertArtifactIsChild(self, artifact, parent):
69+
assert issubclass(artifact.__class__, ArtifactBase)
70+
self.assertEqual(list(artifact.parents), [parent])
71+
72+
def excavation(self):
73+
return self.__class__.CTX
74+
75+
def test_excavated_three_total_artifacts(self):
76+
arfifact_hash_keys = list(self.excavation().hashes.keys())
77+
self.assertEqual(len(arfifact_hash_keys), 3)
78+
79+
def test_excavated_one_top_level_artifact(self):
80+
excavatoin_child_count = len(self.excavation().children)
81+
self.assertEqual(excavatoin_child_count, 1)
82+
83+
def test_produces_top_level_artifact(self):
84+
excavation = self.excavation()
85+
artifact = self.excavation().children[0]
86+
self.assertIsInstance(artifact, ArtifactStream)
87+
self.assertEqual(artifact.digest, '083a3d5e3098aec38ee5d9bc9f9880d3026e120ff8f058782d49ee3ccafd2a6c')
88+
89+
def test_produces_top_level_artifact_whose_parent_is_excavation(self):
90+
artifact = self.excavation().children[0]
91+
self.assertArtifactIsChild(artifact, self.excavation())
92+
93+
def test_produces_two_children_of_the_top_level(self):
94+
artifact = self.excavation().children[0]
95+
artifact_children = sorted(artifact.children, key=lambda a: a.digest)
96+
self.assertEqual(len(artifact_children), 2)
97+
self.assertTrue(artifact_children[0].digest.startswith('79'))
98+
self.assertArtifactIsChild(artifact_children[0], artifact)
99+
self.assertTrue(artifact_children[1].digest.startswith('fa'))
100+
self.assertArtifactIsChild(artifact_children[1], artifact)
101+
102+
if __name__ == '__main__':
103+
unittest.main()

0 commit comments

Comments
 (0)