add tests and did some refactoring