Add (relatively) comprehensive unit tests.

Includes some refactoring to make things testable