Test coverage is usually difficult, most of the times, you just forget about a factor or another.
I usually proceeds in few steps:
- Make sure that it solves a trivial problem (or some)
- Test Edge Cases / Boundary conditions: 0 clause for example
- Test Error Cases: badly formatted input, problems with no solution
- Test Performance / Mass Injection (see if the program does not crash under load, does not leak, ...)
2) and 3) are pretty much interchangeable, 4) should only come if you have ways to investigate this kind of information (benchmarking, memory leak detection...).
An important point is that you should not reverse engineer your code to write the tests, because you would end up testing your code, but not testing that it obeys the specifications.
If it's a home project, specifications are usually informal but they still exist (in your head) and this is after them that you should produce the test cases.