public function renderIterableUsed($subject, Cardinality $cardinality, $isGenerator)
{
$isCall = $subject instanceof Call;
if ($isCall) {
$calls = array($subject);
$renderedCallee = $this->exporter->exportCallable($subject->callback());
} else {
$calls = $subject->allCalls();
$renderedCallee = $this->exporter->exportCallable($subject);
}
$renderedSubject = $this->bold . $renderedCallee . $this->reset;
$minimum = $cardinality->minimum();
$maximum = $cardinality->maximum();
$isNever = null !== $maximum && $maximum < 1;
if ($isCall) {
$totalCount = 1;
if ($isNever) {
$iterableResult = $this->fail;
} else {
$iterableResult = $this->pass;
}
$renderedIterableCount = '';
} else {
$totalCount = 0;
$iterableCount = 0;
foreach ($calls as $call) {
++$totalCount;
if ($isGenerator) {
$isIterable = $call->isGenerator();
} else {
$isIterable = $call->isIterable();
}
if ($isIterable) {
++$iterableCount;
}
}
if ($cardinality->matches($iterableCount, $iterableCount)) {
$iterableResultStart = $this->passStart;
$iterableResultText = self::PASS;
} else {
$iterableResultStart = $this->failStart;
$iterableResultText = self::FAIL;
}
$iterableResult = $iterableResultStart . $iterableResultText . $this->reset;
$matchOrMatches = 1 === $iterableCount ? 'match' : 'matches';
$renderedIterableCount = ' ' . $iterableResultStart . $this->faint . '(' . $iterableCount . ' ' . $matchOrMatches . ')' . $this->reset;
}
if ($isGenerator) {
$renderedIterableType = 'Generator';
} else {
$renderedIterableType = '<iterable>';
}
$renderedCriteria = 'behave like:' . PHP_EOL . ' ' . $iterableResult . ' Returned ' . $renderedIterableType . ', then:' . $renderedIterableCount . PHP_EOL . ' ' . $this->fail . ' Started iterating';
if ($isCall) {
if ($isNever) {
$expected = 'Expected ' . $renderedSubject . ' call #' . $subject->index() . ' not to ' . $renderedCriteria;
} else {
$expected = 'Expected ' . $renderedSubject . ' call #' . $subject->index() . ' to ' . $renderedCriteria;
}
} else {
if ($isGenerator) {
$renderedIterableType = 'generator calls';
} else {
$renderedIterableType = 'iterable calls';
}
if ($isNever) {
$expected = 'Expected ' . $renderedSubject . ' ' . $renderedIterableType . ' not to ' . $renderedCriteria;
} elseif ($cardinality->isAlways()) {
$expected = 'Expected all ' . $renderedSubject . ' ' . $renderedIterableType . ' to ' . $renderedCriteria;
} else {
$expected = 'Expected ' . $renderedSubject . ' ' . $renderedIterableType . ' to ' . $renderedCriteria;
}
}
$renderedCalls = array();
$matchCount = 0;
foreach ($calls as $call) {
if ($isGenerator) {
$callIsRelevant = $call->isGenerator();
} else {
$callIsRelevant = $call->isIterable();
}
if ($callIsRelevant) {
$callStart = '';
$callEnd = '';
} else {
$callStart = $this->faint;
$callEnd = $this->reset;
}
$isMatch = false;
$renderedArguments = array();
foreach ($call->arguments()->all() as $argument) {
$renderedArguments[] = $this->exporter->export($argument, 0);
}
$responseEvent = $call->responseEvent();
if ($responseEvent instanceof ReturnedEvent) {
$returnValue = $responseEvent->value();
if (is_array($returnValue) || $returnValue instanceof Traversable) {
$iterableEvents = $call->iterableEvents();
$renderedIterableEvents = array();
foreach ($iterableEvents as $event) {
if ($event instanceof UsedEvent) {
if ($callIsRelevant) {
$isMatch = true;
if ($isNever) {
$eventResult = $this->fail;
} else {
$eventResult = $this->pass;
}
} else {
$eventResult = '-';
}
$renderedIterableEvents[] = ' ' . $eventResult . ' Started iterating';
} elseif ($event instanceof ProducedEvent) {
$iterableKey = $event->key();
$iterableValue = $event->value();
$renderedIterableEvents[] = ' - Produced ' . $this->exporter->export($iterableKey) . ' => ' . $this->exporter->export($iterableValue);
} elseif ($event instanceof ReceivedEvent) {
$iterableValue = $event->value();
$renderedIterableEvents[] = ' - Received ' . $this->exporter->export($iterableValue);
} elseif ($event instanceof ReceivedExceptionEvent) {
$iterableException = $event->exception();
$renderedIterableEvents[] = ' - Received exception ' . $this->exporter->export($iterableException);
}
}
$endEvent = $call->endEvent();
if (empty($iterableEvents)) {
if ($callIsRelevant) {
if ($isNever) {
$eventResult = $this->pass;
} else {
$eventResult = $this->fail;
}
} else {
$eventResult = '-';
}
$renderedIterableEvents[] = ' ' . $eventResult . ' Never started iterating';
} elseif ($endEvent instanceof ConsumedEvent) {
$renderedIterableEvents[] = ' - Finished iterating';
} elseif ($endEvent instanceof ReturnedEvent) {
$eventValue = $endEvent->value();
$renderedIterableEvents[] = ' - Returned ' . $this->exporter->export($eventValue);
} elseif ($endEvent instanceof ThrewEvent) {
$eventException = $endEvent->exception();
$renderedIterableEvents[] = ' - Threw ' . $this->exporter->export($eventException);
} else {
$renderedIterableEvents[] = ' - Never finished iterating';
}
$renderedResponse = 'Returned ' . $this->exporter->export($returnValue, 0) . ', then:' . $callEnd . PHP_EOL . $callStart . implode($callEnd . PHP_EOL . $callStart, $renderedIterableEvents);
} else {
$renderedResponse = 'Returned ' . $this->exporter->export($returnValue);
}
} elseif ($responseEvent instanceof ThrewEvent) {
$exception = $responseEvent->exception();
$renderedResponse = 'Threw ' . $this->exporter->export($exception);
} else {
$renderedResponse = 'Never responded';
}
if ($isMatch) {
++$matchCount;
}
if ($callIsRelevant) {
if ($isMatch xor $isNever) {
$renderedResult = $this->pass;
} else {
$renderedResult = $this->fail;
}
} else {
$renderedResult = '-';
}
$renderedCalls[] = $callStart . $renderedResult . ' Call #' . $call->index() . ' - ' . $renderedCallee . '(' . implode(', ', $renderedArguments) . '):' . $callEnd . PHP_EOL . $callStart . ' ' . $renderedResult . ' ' . $renderedResponse . $callEnd;
}
$actual = PHP_EOL . implode(PHP_EOL, $renderedCalls);
if ($isCall) {
$cardinality = '';
} else {
$cardinality = $this->renderCardinality($minimum, $maximum, $matchCount, $iterableCount, $totalCount, false);
}
return $this->reset . $expected . $cardinality . $actual;
}