/**
  * Tests wait() and notify() when buffer is empty.
  */
 public function testInputWhenBufferIsEmpty()
 {
     // Initializes a piped input stream.
     $input = new PipedInputStream();
     // Initializes a consumer that reads 1 byte.
     $consumer = new Consumer($input, 1);
     // When started, it will wait because the buffer is empty.
     $consumer->start();
     $this->assertEquals(0, $input->available());
     // Adds contents to the buffer and notify the thread.
     $input->synchronized(function () {
         $buffer = $this->buffer;
         $buffer[] = '*';
         $buffer[] = '*';
         $this->notify();
     });
     // Waits till the thread has finished its job.
     $consumer->join();
     $this->assertEquals(1, $input->available());
     // Asserts the thread is not waiting.
     $this->assertFalse($input->isRunning());
 }
 /**
  * Writes data to a piped output stream, when the buffer of its downstream
  * is full.
  *
  * The producer thread is blocked first. This can be confirmed by checking
  * the 'waiting' status of the downstream object.
  *
  * To wake up the producer thread, a byte is shifted out of the buffer and
  * the downstream is notified.
  *
  * Finally, check the 'waiting' status again to confirm the producer thread
  * has completed its job.
  */
 public function testOutputWhenBufferIsFull()
 {
     // Initializes a piped input stream.
     $downstream = new PipedInputStream();
     // Initializes buffer and fills it up with '*'.
     $buffer = $downstream->buffer;
     for ($i = 0; $i < PipedInputStream::BUFFER_SIZE; $i++) {
         $buffer[] = '*';
     }
     $data = '*';
     // Initializes a piped output stream.
     $output = new PipedOutputStream($downstream);
     // Initializes a producer.
     $producer = new Producer($output, $data);
     // Starts the producer. Because buffer is full, the thread will wait.
     $producer->start();
     // Shifts one byte off the buffer and notify the thread.
     $downstream->synchronized(function () {
         $buffer = $this->buffer;
         $buffer->shift();
         $this->notify();
     });
     // Waits for the thread to finish its job.
     $producer->join();
     $this->assertTrue(true);
     // Now asserts the thread is not waiting.
     $this->assertFalse($downstream->isRunning());
 }