refactor and add tests