<?php
 namespace MongoDB\Tests\SpecTests;
 use Exception;
 use MongoDB\Driver\Exception\BulkWriteException;
 use MongoDB\Driver\Exception\CommandException;
 use MongoDB\Driver\Exception\ExecutionTimeoutException;
 use MongoDB\Driver\Exception\RuntimeException;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Tests\TestCase;
 use stdClass;
 use function get_class;
 use function is_array;
 use function is_string;
 use function sprintf;
 final class ErrorExpectation {
 private static $codeNameMap = [ 'Interrupted' => 11601, 'MaxTimeMSExpired' => 50, 'NoSuchTransaction' => 251, 'OperationNotSupportedInTransaction' => 263, 'WriteConflict' => 112, ];
 private $code;
 private $codeName;
 private $isExpected = false;
 private $excludedLabels = [];
 private $includedLabels = [];
 private $messageContains;
 private function __construct() {
 }
 public static function fromChangeStreams(stdClass $result) {
 $o = new self();
 if (isset($result->error->code)) {
 $o->code = $result->error->code;
 $o->isExpected = true;
 }
 if (isset($result->error->errorLabels)) {
 if (! self::isArrayOfStrings($result->error->errorLabels)) {
 throw InvalidArgumentException::invalidType('errorLabels', $result->error->errorLabels, 'string[]');
 }
 $o->includedLabels = $result->error->errorLabels;
 $o->isExpected = true;
 }
 return $o;
 }
 public static function fromClientSideEncryption(stdClass $operation) {
 return self::fromGenericOperation($operation);
 }
 public static function fromCrud(stdClass $result) {
 $o = new self();
 if (isset($result->error)) {
 $o->isExpected = $result->error;
 }
 return $o;
 }
 public static function fromRetryableReads(stdClass $operation) {
 $o = new self();
 if (isset($operation->error)) {
 $o->isExpected = $operation->error;
 }
 return $o;
 }
 public static function fromRetryableWrites(stdClass $outcome) {
 $o = new self();
 if (isset($outcome->error)) {
 $o->isExpected = $outcome->error;
 }
 return $o;
 }
 public static function fromTransactions(stdClass $operation) {
 return self::fromGenericOperation($operation);
 }
 public static function noError() {
 return new self();
 }
 public function assert(TestCase $test, Exception $actual = null) {
 if (! $this->isExpected) {
 if ($actual !== null) {
 $test->fail(sprintf("Operation threw unexpected %s: %s\n%s", get_class($actual), $actual->getMessage(), $actual->getTraceAsString()));
 }
 return;
 }
 $test->assertNotNull($actual);
 if (isset($this->messageContains) && $this->messageContains !== '') {
 $test->assertStringContainsStringIgnoringCase($this->messageContains, $actual->getMessage());
 }
 if (isset($this->codeName)) {
 $this->assertCodeName($test, $actual);
 }
 if (! empty($this->excludedLabels) || ! empty($this->includedLabels)) {
 $test->assertInstanceOf(RuntimeException::class, $actual);
 foreach ($this->excludedLabels as $label) {
 $test->assertFalse($actual->hasErrorLabel($label), 'Exception should not have error label: ' . $label);
 }
 foreach ($this->includedLabels as $label) {
 $test->assertTrue($actual->hasErrorLabel($label), 'Exception should have error label: ' . $label);
 }
 }
 }
 public function isExpected() {
 return $this->isExpected;
 }
 private function assertCodeName(TestCase $test, Exception $actual = null) {
 if ($actual instanceof BulkWriteException || $actual instanceof ExecutionTimeoutException) {
 $test->assertArrayHasKey($this->codeName, self::$codeNameMap);
 $test->assertSame(self::$codeNameMap[$this->codeName], $actual->getCode());
 return;
 }
 $test->assertInstanceOf(CommandException::class, $actual);
 $result = $actual->getResultDocument();
 if (isset($result->writeConcernError)) {
 $test->assertObjectHasAttribute('codeName', $result->writeConcernError);
 $test->assertSame($this->codeName, $result->writeConcernError->codeName);
 return;
 }
 $test->assertObjectHasAttribute('codeName', $result);
 $test->assertSame($this->codeName, $result->codeName);
 }
 private static function fromGenericOperation(stdClass $operation) {
 $o = new self();
 if (isset($operation->error)) {
 $o->isExpected = $operation->error;
 }
 $result = isset($operation->result) ? $operation->result : null;
 if (isset($result->errorContains)) {
 $o->messageContains = $result->errorContains;
 $o->isExpected = true;
 }
 if (isset($result->errorCodeName)) {
 $o->codeName = $result->errorCodeName;
 $o->isExpected = true;
 }
 if (isset($result->errorLabelsContain)) {
 if (! self::isArrayOfStrings($result->errorLabelsContain)) {
 throw InvalidArgumentException::invalidType('errorLabelsContain', $result->errorLabelsContain, 'string[]');
 }
 $o->includedLabels = $result->errorLabelsContain;
 $o->isExpected = true;
 }
 if (isset($result->errorLabelsOmit)) {
 if (! self::isArrayOfStrings($result->errorLabelsOmit)) {
 throw InvalidArgumentException::invalidType('errorLabelsOmit', $result->errorLabelsOmit, 'string[]');
 }
 $o->excludedLabels = $result->errorLabelsOmit;
 $o->isExpected = true;
 }
 return $o;
 }
 private static function isArrayOfStrings($array) {
 if (! is_array($array)) {
 return false;
 }
 foreach ($array as $string) {
 if (! is_string($string)) {
 return false;
 }
 }
 return true;
 }
 }
 