refactored and add some tests