makes this more generic and adds lots of tests