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.