diff --git a/src/Vision/V1/ImageAnnotatorClient.php b/src/Vision/V1/ImageAnnotatorClient.php index 94d825495aff..8f239421e537 100644 --- a/src/Vision/V1/ImageAnnotatorClient.php +++ b/src/Vision/V1/ImageAnnotatorClient.php @@ -30,13 +30,458 @@ namespace Google\Cloud\Vision\V1; +use Google\ApiCore\ApiException; +use Google\ApiCore\ArrayTrait; +use Google\ApiCore\RetrySettings; +use Google\Cloud\Vision\VisionHelpersTrait; use Google\Cloud\Vision\V1\Gapic\ImageAnnotatorGapicClient; +use InvalidArgumentException; /** * {@inheritdoc} */ class ImageAnnotatorClient extends ImageAnnotatorGapicClient { - // This class is intentionally empty, and is intended to hold manual - // additions to the generated {@see ImageAnnotatorClientImpl} class. + use VisionHelpersTrait; + + /** + * Creates an Image object that can be used as part of an image annotation request. + * + * Example: + * ``` + * //[snippet=resource] + * $imageResource = fopen('path/to/image.jpg', 'r'); + * $image = $imageAnnotatorClient->createImageObject($imageResource); + * $response = $imageAnnotatorClient->faceDetection($image); + * ``` + * + * ``` + * //[snippet=data] + * $imageData = file_get_contents('path/to/image.jpg'); + * $image = $imageAnnotatorClient->createImageObject($imageData); + * $response = $imageAnnotatorClient->faceDetection($image); + * ``` + * + * ``` + * //[snippet=url] + * $imageUri = "gs://my-bucket/image.jpg"; + * $image = $imageAnnotatorClient->createImageObject($imageUri); + * $response = $imageAnnotatorClient->faceDetection($image); + * ``` + * + * @param resource|string $imageInput An image to configure with + * the given settings. This parameter will accept a resource, a + * string of bytes, or the URI of an image in a publicly-accessible + * web location. + * @return Image + * @throws InvalidArgumentException + */ + public function createImageObject($imageInput) + { + return $this->createImageHelper(Image::class, ImageSource::class, $imageInput); + } + + /** + * Run image detection and annotation for an image. + * + * Example: + * ``` + * use Google\Cloud\Vision\V1\Feature; + * use Google\Cloud\Vision\V1\Feature_Type; + * + * $imageResource = fopen('path/to/image.jpg', 'r'); + * $features = [Feature_Type::FACE_DETECTION]; + * $response = $imageAnnotatorClient->annotateImage($imageResource, $features); + * ``` + * + * @param resource|string|Image $image The image to be processed. + * @param Feature[]|int[] $features Requested features. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function annotateImage($image, $features, $optionalArgs = []) + { + $image = $this->createImageObject($image); + return $this->annotateImageHelper( + [$this, 'batchAnnotateImages'], + AnnotateImageRequest::class, + $image, + $features, + $optionalArgs + ); + } + + /** + * Run face detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->faceDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function faceDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::FACE_DETECTION, + $optionalArgs + ); + } + + /** + * Run landmark detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->landmarkDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function landmarkDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::LANDMARK_DETECTION, + $optionalArgs + ); + } + + /** + * Run logo detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->logoDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function logoDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::LOGO_DETECTION, + $optionalArgs + ); + } + + /** + * Run label detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->labelDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function labelDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::LABEL_DETECTION, + $optionalArgs + ); + } + + /** + * Run text detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->textDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function textDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::TEXT_DETECTION, + $optionalArgs + ); + } + + /** + * Run document text detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->documentTextDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function documentTextDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::DOCUMENT_TEXT_DETECTION, + $optionalArgs + ); + } + + /** + * Run safe search detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->safeSearchDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function safeSearchDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::SAFE_SEARCH_DETECTION, + $optionalArgs + ); + } + + /** + * Run image properties detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->imagePropertiesDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function imagePropertiesDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::IMAGE_PROPERTIES, + $optionalArgs + ); + } + + /** + * Run crop hints detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->cropHintsDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function cropHintsDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::CROP_HINTS, + $optionalArgs + ); + } + + /** + * Run web detection for an image. + * + * Example: + * ``` + * $imageContent = file_get_contents('path/to/image.jpg'); + * $response = $imageAnnotatorClient->webDetection($imageContent); + * ``` + * + * @param Image $image An image annotation request. + * @param array $optionalArgs { + * Configuration Options. + * + * @type ImageContext $imageContext Additional context that may accompany the image. + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a + * {@see Google\ApiCore\RetrySettings} object, or an associative array + * of retry settings parameters. See the documentation on + * {@see Google\ApiCore\RetrySettings} for example usage. + * } + * + * @return AnnotateImageResponse + * + * @throws ApiException if the remote call fails + * @experimental + */ + public function webDetection($image, $optionalArgs = []) + { + return $this->annotateSingleFeature( + $image, + Feature_Type::WEB_DETECTION, + $optionalArgs + ); + } + + /** + * @param Image $image + * @param Feature|int $featureType + * @param array $optionalArgs + * @return AnnotateImageResponse + */ + private function annotateSingleFeature($image, $featureType, $optionalArgs) + { + return $this->annotateImage($image, [$featureType], $optionalArgs); + } } diff --git a/src/Vision/VisionHelpersTrait.php b/src/Vision/VisionHelpersTrait.php new file mode 100644 index 000000000000..4a5f5fd27b03 --- /dev/null +++ b/src/Vision/VisionHelpersTrait.php @@ -0,0 +1,121 @@ +setImage($image); + $features = $this->buildFeatureList(Feature::class, $features); + $request->setFeatures($features); + $imageContext = $this->pluck('imageContext', $optionalArgs, false); + if (!is_null($imageContext)) { + $request->setImageContext($imageContext); + } + return $callback([$request], $optionalArgs)->getResponses()[0]; + } + + /** + * @param string $featureClass + * @param Feature[]|int[] $featureTypes + * @return Feature[]|array + */ + private function buildFeatureList($featureClass, $featureTypes) + { + $features = []; + foreach ($featureTypes as $featureType) { + if (is_int($featureType)) { + $feature = new $featureClass(); + $feature->setType($featureType); + } else { + $feature = $featureType; + } + $features[] = $feature; + } + return $features; + } + + /** + * @param string $imageClass + * @param string $imageSourceClass + * @param string|resource|Image|mixed $imageInput + * @return Image|mixed + */ + private function createImageHelper($imageClass, $imageSourceClass, $imageInput) + { + if (is_object($imageInput) && is_a($imageInput, $imageClass)) { + return $imageInput; + } + $image = new $imageClass(); + if (is_string($imageInput)) { + if (in_array(parse_url($imageInput, PHP_URL_SCHEME), $this->urlSchemes)) { + $imageSource = new $imageSourceClass(); + $imageSource->setImageUri($imageInput); + $image->setSource($imageSource); + } else { + $image->setContent($imageInput); + } + } elseif (is_resource($imageInput)) { + $image->setContent(stream_get_contents($imageInput)); + } else { + throw new InvalidArgumentException( + 'Given image is not valid. ' . + 'Image must be a string of bytes, a valid image URI, or a resource.' + ); + } + return $image; + } +} diff --git a/tests/snippets/Vision/V1/ImageAnnotatorClientTest.php b/tests/snippets/Vision/V1/ImageAnnotatorClientTest.php new file mode 100644 index 000000000000..a54af74de124 --- /dev/null +++ b/tests/snippets/Vision/V1/ImageAnnotatorClientTest.php @@ -0,0 +1,149 @@ +transport = $this->prophesize(TransportInterface::class); + $this->client = new ImageAnnotatorClient([ + 'transport' => $this->transport->reveal(), + ]); + } + + /** + * @dataProvider createImageObjectSnippetsDataProvider + */ + public function testCreateImageObjectSnippets($snippetName) + { + $snippet = $this->snippetFromMethod( + ImageAnnotatorClient::class, + 'createImageObject', + $snippetName + ); + $snippet->addLocal('imageAnnotatorClient', $this->client); + + $snippet->replace( + "path/to/image.jpg", + "php://temp" + ); + + $this->transport->startUnaryCall(Argument::type(Call::class), Argument::type('array')) + ->shouldBeCalledTimes(1) + ->willReturn($this->getPromisedResponse()); + + $res = $snippet->invoke('image'); + + $this->assertInstanceOf(Image::class, $res->returnVal()); + } + + public function createImageObjectSnippetsDataProvider() + { + return [ + ['resource'], + ['data'], + ['url'] + ]; + } + + public function testAnnotateImage() + { + $snippet = $this->snippetFromMethod(ImageAnnotatorClient::class, 'annotateImage'); + $snippet->addLocal('imageAnnotatorClient', $this->client); + + $snippet->replace( + "path/to/image.jpg", + "php://temp" + ); + + $this->transport->startUnaryCall(Argument::type(Call::class), Argument::type('array')) + ->shouldBeCalledTimes(1) + ->willReturn($this->getPromisedResponse()); + + $res = $snippet->invoke('response'); + + $this->assertInstanceOf(AnnotateImageResponse::class, $res->returnVal()); + } + + /** + * @dataProvider detectionMethodSnippetDataProvider + */ + public function testDetectionMethodSnippet($method) + { + $snippet = $this->snippetFromMethod(ImageAnnotatorClient::class, $method); + $snippet->addLocal('imageAnnotatorClient', $this->client); + + $snippet->replace( + "path/to/image.jpg", + "php://temp" + ); + + + $this->transport->startUnaryCall(Argument::type(Call::class), Argument::type('array')) + ->shouldBeCalledTimes(1) + ->willReturn($this->getPromisedResponse()); + + $res = $snippet->invoke('response'); + + $this->assertInstanceOf(AnnotateImageResponse::class, $res->returnVal()); + } + + public function detectionMethodSnippetDataProvider() + { + return [ + ['faceDetection'], + ['landmarkDetection'], + ['logoDetection'], + ['labelDetection'], + ['textDetection'], + ['documentTextDetection'], + ['safeSearchDetection'], + ['imagePropertiesDetection'], + ['cropHintsDetection'], + ['webDetection'], + ]; + } + + private function getPromisedResponse() + { + $expectedAnnotationResponses = [new AnnotateImageResponse()]; + $expectedResponse = new BatchAnnotateImagesResponse(); + $expectedResponse->setResponses($expectedAnnotationResponses); + return new FulfilledPromise( + $expectedResponse + ); + } +} diff --git a/tests/unit/Vision/V1/ImageAnnotatorClientTest.php b/tests/unit/Vision/V1/ImageAnnotatorClientTest.php new file mode 100644 index 000000000000..a85515d29271 --- /dev/null +++ b/tests/unit/Vision/V1/ImageAnnotatorClientTest.php @@ -0,0 +1,206 @@ +transport = $this->prophesize(TransportInterface::class); + $this->client = new ImageAnnotatorClient([ + 'transport' => $this->transport->reveal(), + ]); + } + + public function testCreateImageObject() + { + $image = $this->client->createImageObject("gs://my-bucket/myimage.jpg"); + $this->assertSame(Image::class, get_class($image)); + $this->assertSame(ImageSource::class, get_class($image->getSource())); + } + + /** + * @dataProvider annotateImageDataProvider + */ + public function testAnnotateImage($image, $features) + { + $expectedAnnotationResponses = [new AnnotateImageResponse()]; + $expectedResponse = new BatchAnnotateImagesResponse(); + $expectedResponse->setResponses($expectedAnnotationResponses); + $this->transport->startUnaryCall(Argument::type(Call::class), Argument::type('array')) + ->shouldBeCalledTimes(1) + ->willReturn( + new FulfilledPromise( + $expectedResponse + ) + ); + + $res = $this->client->annotateImage($image, $features); + + $this->assertInstanceOf(AnnotateImageResponse::class, $res); + } + + public function annotateImageDataProvider() + { + return [ + [$this->createImageObject('foobar'), [(new Feature())->setType(Feature_Type::FACE_DETECTION)]], + ['foobar', [Feature_Type::FACE_DETECTION]], + ]; + } + + public function testAnnotateImageWithImageContext() + { + $image = $this->client->createImageObject('foobar'); + $featureType = Feature_Type::FACE_DETECTION; + $imageContext = new ImageContext(); + $imageContext->setLanguageHints(['en']); + + $expectedFeature = new Feature(); + $expectedFeature->setType($featureType); + $expectedFeatures = [$expectedFeature]; + $expectedRequest = new AnnotateImageRequest(); + $expectedRequest->setImage($image); + $expectedRequest->setFeatures($expectedFeatures); + $expectedRequest->setImageContext($imageContext); + $expectedRequests = [$expectedRequest]; + + $expectedMessage = new BatchAnnotateImagesRequest(); + $expectedMessage->setRequests($expectedRequests); + + $expectedAnnotationResponses = [new AnnotateImageResponse()]; + $expectedResponse = new BatchAnnotateImagesResponse(); + $expectedResponse->setResponses($expectedAnnotationResponses); + $this->transport->startUnaryCall( Argument::allOf( + Argument::type(Call::class), + Argument::which('getMethod', 'google.cloud.vision.v1.ImageAnnotator/BatchAnnotateImages'), + Argument::which('getMessage', $expectedMessage) + ), + Argument::type('array') + ) + ->shouldBeCalledTimes(1) + ->willReturn( + new FulfilledPromise( + $expectedResponse + ) + ); + + $feature = new Feature(); + $feature->setType($featureType); + $features = [$feature]; + + $res = $this->client->annotateImage($image, $features, [ + 'imageContext' => $imageContext, + ]); + + $this->assertInstanceOf(AnnotateImageResponse::class, $res); + } + + /** + * @dataProvider detectionMethodDataProvider + */ + public function testDetectionMethod($methodName, $featureType, $image) + { + $expectedFeature = new Feature(); + $expectedFeature->setType($featureType); + $expectedFeatures = [$expectedFeature]; + $expectedRequest = new AnnotateImageRequest(); + $expectedRequest->setImage($this->createImageObject($image)); + $expectedRequest->setFeatures($expectedFeatures); + $expectedRequests = [$expectedRequest]; + + $expectedMessage = new BatchAnnotateImagesRequest(); + $expectedMessage->setRequests($expectedRequests); + + $expectedAnnotationResponses = [new AnnotateImageResponse()]; + $expectedResponse = new BatchAnnotateImagesResponse(); + $expectedResponse->setResponses($expectedAnnotationResponses); + $this->transport->startUnaryCall( + Argument::allOf( + Argument::type(Call::class), + Argument::which('getMethod', 'google.cloud.vision.v1.ImageAnnotator/BatchAnnotateImages'), + Argument::which('getMessage', $expectedMessage) + ), + Argument::type('array') + ) + ->shouldBeCalledTimes(1) + ->willReturn( + new FulfilledPromise( + $expectedResponse + ) + ); + + $res = $this->client->$methodName($image); + + $this->assertInstanceOf(AnnotateImageResponse::class, $res); + } + + public function detectionMethodDataProvider() + { + $items = [ + ['faceDetection', Feature_Type::FACE_DETECTION], + ['landmarkDetection', Feature_Type::LANDMARK_DETECTION], + ['logoDetection', Feature_Type::LOGO_DETECTION], + ['labelDetection', Feature_Type::LABEL_DETECTION], + ['textDetection', Feature_Type::TEXT_DETECTION], + ['documentTextDetection', Feature_Type::DOCUMENT_TEXT_DETECTION], + ['safeSearchDetection', Feature_Type::SAFE_SEARCH_DETECTION], + ['imagePropertiesDetection', Feature_Type::IMAGE_PROPERTIES], + ['cropHintsDetection', Feature_Type::CROP_HINTS], + ['webDetection', Feature_Type::WEB_DETECTION], + ]; + $data = []; + foreach ($items as $item) { + $item[] = 'foobar'; + $item[] = $this->createImageObject('foobar'); + $data[] = $item; + } + return $data; + } + + private function createImageObject($imageInput) + { + return $this->createImageHelper(Image::class, ImageSource::class, $imageInput); + } +} diff --git a/tests/unit/Vision/VisionHelpersTraitTest.php b/tests/unit/Vision/VisionHelpersTraitTest.php new file mode 100644 index 000000000000..853daffa78d8 --- /dev/null +++ b/tests/unit/Vision/VisionHelpersTraitTest.php @@ -0,0 +1,146 @@ +implementation = \Google\Cloud\Core\Testing\TestHelpers::impl(VisionHelpersTrait::class); + } + + public function testAnnotateImageHelper() + { + $image = new Image(); + $featureType = Feature_Type::FACE_DETECTION; + $feature = new Feature(); + $feature->setType($featureType); + $features = [$feature]; + $imageContext = new ImageContext(); + $imageContext->setLanguageHints(['en']); + + $cb = function ($requests, $optionalArgs) use ($image, $features, $imageContext) { + + // Test that imageContext key is correctly stripped + $this->assertArrayNotHasKey('imageContext', $optionalArgs); + + $this->assertSame(1, count($requests)); + $request = $requests[0]; + $this->assertEquals($image, $request->getImage()); + // Use iterator_to_array to convert protobuf Repeated Field object to array for comparison + $this->assertSame($features, iterator_to_array($request->getFeatures())); + $this->assertSame($imageContext, $request->getImageContext()); + + $response = new BatchAnnotateImagesResponse(); + $response->setResponses([new AnnotateImageResponse()]); + return $response; + }; + + $response = $this->implementation->call('annotateImageHelper', [ + $cb, + AnnotateImageRequest::class, + $image, + $features, + ['imageContext' => $imageContext] + ]); + + $this->assertEquals(AnnotateImageResponse::class, get_class($response)); + } + + /** + * @dataProvider createImageHelperDataProvider + */ + public function testCreateImageHelper($imageInput, $expectedContent, $expectedUri) + { + $image = $this->implementation->call('createImageHelper', [ + Image::class, + ImageSource::class, + $imageInput + ]); + $this->assertSame($expectedContent, $image->getContent()); + $imageSource = $image->getSource(); + $this->assertSame($expectedUri, is_null($imageSource) ? null : $imageSource->getImageUri()); + } + + public function createImageHelperDataProvider() + { + $content = 'imageresourcecontent'; + $stream = fopen('php://memory','r+'); + fwrite($stream, $content); + rewind($stream); + return [ + ["http://my.site/myimage.jpg", "", "http://my.site/myimage.jpg"], + ["https://my.site/myimage.jpg", "", "https://my.site/myimage.jpg"], + ["gs://my_bucket/myimage.jpg", "", "gs://my_bucket/myimage.jpg"], + ["abcdefxyz", "abcdefxyz", null], + [$stream, $content, null], + [ + $this->createImageHelper(Image::class, ImageSource::class, 'foobar'), + 'foobar', + null + ], + [ + $this->createImageHelper(Image::class, ImageSource::class, 'https://my.site/myimage.jpg'), + '', + 'https://my.site/myimage.jpg' + ], + ]; + } + + /** + * @dataProvider invalidCreateImageHelperDataProvider + * @expectedException InvalidArgumentException + */ + public function testInvalidCreateImageHelper($imageInput) + { + $this->implementation->call('createImageHelper', [ + Image::class, + ImageSource::class, + $imageInput + ]); + } + + public function invalidCreateImageHelperDataProvider() + { + return [ + [null], + [5], + ]; + } +} +