diff --git a/tests/test_typedict.py b/tests/test_typedict.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe19bcf2b869fe3aa43f5359aa6e16db642044e1
--- /dev/null
+++ b/tests/test_typedict.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+#
+# test_typedict.py -
+#
+# Author: Paul McCarthy <pauldmccarthy@gmail.com>
+#
+
+import itertools as it
+import pytest
+
+import fsl.utils.typedict as typedict
+
+
+def test_create():
+    
+    td = typedict.TypeDict()
+
+
+    assert len(td)          == 0
+    assert len(td.keys())   == 0
+    assert len(td.values()) == 0
+    assert len(td.items())  == 0
+
+    keys   = [0,
+              1,
+              2,
+              'a',
+              'b',
+              'c',
+              'a.b',
+              'a.b.c',
+              ('a', 'c'),
+              ('a',  0)]
+    values = list(range(len(keys)))
+    
+    td = typedict.TypeDict(        dict(zip(keys, values)))
+    td = typedict.TypeDict(initial=dict(zip(keys, values)))
+
+    print(     td)
+    print(repr(td))
+
+    tknkeys = [td.tokenifyKey(k) for k in keys]
+
+    assert len(td)                   == len(keys)
+    assert list(sorted(td.keys()))   == list(sorted(tknkeys))
+    assert list(sorted(td.values())) == list(sorted(values))
+    assert list(sorted(td.items()))  == list(sorted(zip(tknkeys, values)))
+
+    for k, v in zip(keys, values):
+        assert td[k] == v
+
+    with pytest.raises(KeyError):
+        td['non-existent']
+
+    assert td.get('non-existent') is None
+    assert td.get('non-existent', 'default') == 'default'
+
+
+def test_class_keys():
+
+    class A(object):
+        pass
+
+    class B(object):
+        pass
+
+    class C(object):
+        pass
+
+    td = typedict.TypeDict()
+
+    a  = A()
+    b  = B()
+    c  = C()
+
+    # TypeDict [currently] does not allow value
+    # assignment with classes/instances as keys -
+    # we must use the class name, encoded as a
+    # string, when assigning.
+    keycomponents = ['A', 'B', 'C', 'att1', 'att2', 'att3']
+    keys          = list(it.chain(it.permutations(keycomponents, 1),
+                                  it.permutations(keycomponents, 2),
+                                  it.permutations(keycomponents, 3),
+                                  it.permutations(keycomponents, 4),
+                                  it.permutations(keycomponents, 5),
+                                  it.permutations(keycomponents, 6)))
+
+    for val, key in enumerate(keys):
+        if len(key) == 1: td[key[0]] = val
+        else:             td[key]    = val
+
+    for val, key in enumerate(keys):
+
+        # Keys can be passed as tuples
+        assert td[key] == val
+
+        # Or as dot-separated strings
+        assert td['.'.join(key)] == val
+
+        # But when accessing items,
+        # we can use either class names,
+        # classes, or instances.
+        for toReplace in it.chain(it.combinations(['A', 'B', 'C'], 1),
+                                  it.combinations(['A', 'B', 'C'], 2),
+                                  it.combinations(['A', 'B', 'C'], 3)):
+
+            clsrep  = {'A' : A, 'B' : B, 'C' : C}
+            instrep = {'A' : a, 'B' : b, 'C' : c}
+
+            # use class instead of name
+            repkey = [clsrep[k] if k in toReplace else k for k in key]
+            assert td[repkey] == val
+
+            # use instance instead of name
+            repkey = [instrep[k] if k in toReplace else k for k in key]
+            assert td[repkey] == val
+
+
+def test_class_hierarchy():
+
+    class A(object):
+        pass
+
+    class B(A):
+        pass
+
+    td = typedict.TypeDict()
+    td['A.a'] = 'A.a'
+    td['A.b'] = 'A.b'
+    td['A.c'] = 'A.c'
+    td['A.d'] = 'A.d'
+    td['B.a'] = 'B.a'
+    td['B.b'] = 'B.b'
+    td['B.1'] = 'B.1'
+    td['B.2'] = 'B.2'
+
+    a = A()
+    b = B()
+    
+    assert td[A, 'a'] == 'A.a'
+    assert td[A, 'b'] == 'A.b'
+    assert td[A, 'c'] == 'A.c'
+    assert td[A, 'd'] == 'A.d'
+    
+    assert td['A.a']  == 'A.a'
+    assert td['A.b']  == 'A.b'
+    assert td['A.c']  == 'A.c'
+    assert td['A.d']  == 'A.d'
+    
+    assert td.get((A, 'a')) == 'A.a'
+    assert td.get((A, 'b')) == 'A.b'
+    assert td.get((A, 'c')) == 'A.c'
+    assert td.get((A, 'd')) == 'A.d' 
+    
+    assert td.get((A, 'a'), allhits=True) == ['A.a']
+    assert td.get((A, 'b'), allhits=True) == ['A.b']
+    assert td.get((A, 'c'), allhits=True) == ['A.c']
+    assert td.get((A, 'd'), allhits=True) == ['A.d']
+    
+    assert td.get((a, 'a'), allhits=True) == ['A.a']
+    assert td.get((a, 'b'), allhits=True) == ['A.b']
+    assert td.get((a, 'c'), allhits=True) == ['A.c']
+    assert td.get((a, 'd'), allhits=True) == ['A.d']
+
+    assert td[B, 'a'] == 'B.a'
+    assert td[B, 'b'] == 'B.b'
+    assert td[B, '1'] == 'B.1'
+    assert td[B, '2'] == 'B.2'
+    
+    assert td['B.a']  == 'B.a'
+    assert td['B.b']  == 'B.b'
+    assert td['B.1']  == 'B.1'
+    assert td['B.2']  == 'B.2'
+    
+    assert td.get('B.a') == 'B.a'
+    assert td.get('B.b') == 'B.b'
+    assert td.get('B.1') == 'B.1'
+    assert td.get('B.2') == 'B.2'
+
+    assert td.get((B, 'a')) == 'B.a'
+    assert td.get((B, 'b')) == 'B.b'
+    assert td.get((B, '1')) == 'B.1'
+    assert td.get((B, '2')) == 'B.2'
+    assert td.get((b, 'a')) == 'B.a'
+    assert td.get((b, 'b')) == 'B.b'
+    assert td.get((b, '1')) == 'B.1'
+    assert td.get((b, '2')) == 'B.2'
+
+    with pytest.raises(KeyError):
+        td['B.c']
+    with pytest.raises(KeyError):
+        td['B.d']
+
+    assert td[B, 'c'] == 'A.c'
+    assert td[B, 'd'] == 'A.d'
+    assert td[b, 'c'] == 'A.c'
+    assert td[b, 'd'] == 'A.d' 
+    
+    assert td.get('B.a',    allhits=True) == ['B.a']
+    assert td.get('B.b',    allhits=True) == ['B.b']
+    assert td.get('B.1',    allhits=True) == ['B.1']
+    assert td.get('B.2',    allhits=True) == ['B.2'] 
+    assert td.get((B, 'a'), allhits=True) == ['B.a', 'A.a']
+    assert td.get((B, 'b'), allhits=True) == ['B.b', 'A.b']
+    assert td.get((B, '1'), allhits=True) == ['B.1']
+    assert td.get((B, '2'), allhits=True) == ['B.2']
+    assert td.get((B, 'c'), allhits=True) == ['A.c']
+    assert td.get((B, 'd'), allhits=True) == ['A.d'] 
+    
+    assert td.get((b, 'a'), allhits=True) == ['B.a', 'A.a']
+    assert td.get((b, 'b'), allhits=True) == ['B.b', 'A.b']
+    assert td.get((b, '1'), allhits=True) == ['B.1']
+    assert td.get((b, '2'), allhits=True) == ['B.2']
+    assert td.get((b, 'c'), allhits=True) == ['A.c']
+
+    assert td.get((B, 'a'), allhits=False, bykey=True) == 'B.a'
+    assert td.get((B, 'b'), allhits=False, bykey=True) == 'B.b'
+    assert td.get((B, '1'), allhits=False, bykey=True) == 'B.1'
+    assert td.get((B, '2'), allhits=False, bykey=True) == 'B.2'
+    
+    assert td.get((B, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a',
+                                                           ('B', 'a') : 'B.a'}
+    assert td.get((B, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b',
+                                                           ('B', 'b') : 'B.b'}
+    assert td.get((B, '1'), allhits=True,  bykey=True) == {('B', '1') : 'B.1'}
+    assert td.get((B, '2'), allhits=True,  bykey=True) == {('B', '2') : 'B.2'}
+    assert td.get((B, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
+    assert td.get((B, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'} 
+    
+    assert td.get((b, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a',
+                                                           ('B', 'a') : 'B.a'}
+    assert td.get((b, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b',
+                                                           ('B', 'b') : 'B.b'}
+    assert td.get((b, '1'), allhits=True,  bykey=True) == {('B', '1') : 'B.1'}
+    assert td.get((b, '2'), allhits=True,  bykey=True) == {('B', '2') : 'B.2'}
+    assert td.get((b, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
+    assert td.get((b, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'} 
+    
+    assert td.get((A, 'a'), allhits=True,  bykey=True) == {('A', 'a') : 'A.a'}
+    assert td.get((A, 'b'), allhits=True,  bykey=True) == {('A', 'b') : 'A.b'}
+    assert td.get((A, 'c'), allhits=True,  bykey=True) == {('A', 'c') : 'A.c'}
+    assert td.get((A, 'd'), allhits=True,  bykey=True) == {('A', 'd') : 'A.d'}