<?php
 namespace MongoDB\Tests;
 use InvalidArgumentException;
 use MongoDB\Driver\ReadConcern;
 use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Tests\Compat\PolyfillAssertTrait;
 use PHPUnit\Framework\TestCase as BaseTestCase;
 use ReflectionClass;
 use stdClass;
 use Traversable;
 use function array_map;
 use function array_merge;
 use function array_values;
 use function call_user_func;
 use function getenv;
 use function hash;
 use function is_array;
 use function is_object;
 use function iterator_to_array;
 use function MongoDB\BSON\fromPHP;
 use function MongoDB\BSON\toJSON;
 use function restore_error_handler;
 use function set_error_handler;
 use function sprintf;
 use const E_USER_DEPRECATED;
 abstract class TestCase extends BaseTestCase {
 use PolyfillAssertTrait;
 public static function getUri() {
 return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017';
 }
 public function assertMatchesDocument($expectedDocument, $actualDocument) {
 $normalizedExpectedDocument = $this->normalizeBSON($expectedDocument);
 $normalizedActualDocument = $this->normalizeBSON($actualDocument);
 $extraKeys = [];
 foreach ($normalizedActualDocument as $key => $value) {
 if (! $normalizedExpectedDocument->offsetExists($key)) {
 $extraKeys[] = $key;
 }
 }
 foreach ($extraKeys as $key) {
 $normalizedActualDocument->offsetUnset($key);
 }
 $this->assertEquals( toJSON(fromPHP($normalizedExpectedDocument)), toJSON(fromPHP($normalizedActualDocument)) );
 }
 public function assertSameDocument($expectedDocument, $actualDocument) {
 $this->assertEquals( toJSON(fromPHP($this->normalizeBSON($expectedDocument))), toJSON(fromPHP($this->normalizeBSON($actualDocument))) );
 }
 public function assertSameDocuments(array $expectedDocuments, $actualDocuments) {
 if ($actualDocuments instanceof Traversable) {
 $actualDocuments = iterator_to_array($actualDocuments);
 }
 if (! is_array($actualDocuments)) {
 throw new InvalidArgumentException('$actualDocuments is not an array or Traversable');
 }
 $normalizeRootDocuments = function ($document) {
 return toJSON(fromPHP($this->normalizeBSON($document)));
 }
;
 $this->assertEquals( array_map($normalizeRootDocuments, $expectedDocuments), array_map($normalizeRootDocuments, $actualDocuments) );
 }
 public function provideInvalidArrayValues() {
 return $this->wrapValuesForDataProvider($this->getInvalidArrayValues());
 }
 public function provideInvalidDocumentValues() {
 return $this->wrapValuesForDataProvider($this->getInvalidDocumentValues());
 }
 protected function assertDeprecated(callable $execution) {
 $errors = [];
 set_error_handler(function ($errno, $errstr) use (&$errors) {
 $errors[] = $errstr;
 }
, E_USER_DEPRECATED);
 try {
 call_user_func($execution);
 }
 finally {
 restore_error_handler();
 }
 $this->assertCount(1, $errors);
 }
 protected function getCollectionName() {
 $class = new ReflectionClass($this);
 return sprintf('%s.%s', $class->getShortName(), hash('crc32b', $this->getName()));
 }
 protected function getDatabaseName() {
 return getenv('MONGODB_DATABASE') ?: 'phplib_test';
 }
 protected function getInvalidArrayValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true, new stdClass()], $includeNull ? [null] : []);
 }
 protected function getInvalidBooleanValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', [], new stdClass()], $includeNull ? [null] : []);
 }
 protected function getInvalidDocumentValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true], $includeNull ? [null] : []);
 }
 protected function getInvalidIntegerValues($includeNull = false) {
 return array_merge([3.14, 'foo', true, [], new stdClass()], $includeNull ? [null] : []);
 }
 protected function getInvalidReadConcernValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
 }
 protected function getInvalidReadPreferenceValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new WriteConcern(1)], $includeNull ? [null] : []);
 }
 protected function getInvalidSessionValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
 }
 protected function getInvalidStringValues($includeNull = false) {
 return array_merge([123, 3.14, true, [], new stdClass()], $includeNull ? [null] : []);
 }
 protected function getInvalidWriteConcernValues($includeNull = false) {
 return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY)], $includeNull ? [null] : []);
 }
 protected function getNamespace() {
 return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName());
 }
 protected function wrapValuesForDataProvider(array $values) {
 return array_map(function ($value) {
 return [$value];
 }
, $values);
 }
 private function normalizeBSON($bson) {
 if (! is_array($bson) && ! is_object($bson)) {
 throw new InvalidArgumentException('$bson is not an array or object');
 }
 if ($bson instanceof BSONArray || (is_array($bson) && $bson === array_values($bson))) {
 if (! $bson instanceof BSONArray) {
 $bson = new BSONArray($bson);
 }
 }
 else {
 if (! $bson instanceof BSONDocument) {
 $bson = new BSONDocument((array) $bson);
 }
 $bson->ksort();
 }
 foreach ($bson as $key => $value) {
 if ($value instanceof BSONArray || (is_array($value) && $value === array_values($value))) {
 $bson[$key] = $this->normalizeBSON($value);
 continue;
 }
 if ($value instanceof stdClass || $value instanceof BSONDocument || is_array($value)) {
 $bson[$key] = $this->normalizeBSON($value);
 continue;
 }
 }
 return $bson;
 }
 }
 