fix(lock): fix bug and improve semaphore test coverage

Calling Unlock() on a Lock that did not hold the semaphore would panic
when the semaphore had >0 (other) holders.
Added test coverage for all Semaphore actions.