first commit

This commit is contained in:
2024-11-10 21:08:49 +01:00
commit 0d932ce5ee
14455 changed files with 2567501 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\AbstractConverter;
use WebPConvert\Tests\Convert\Exposers\AbstractConverterExposer;
use WebPConvert\Tests\Convert\TestConverters\ExposedConverter;
use WebPConvert\Tests\Convert\TestConverters\SuccessGuaranteedConverter;
use PHPUnit\Framework\TestCase;
class AbstractConverterTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
SuccessGuaranteedConverter::convert(
self::getImagePath('test.jpg'),
self::getImagePath('test.webp')
);
$this->addToAssertionCount(1);
}
public function testMimeTypeGuesser()
{
//$this->assertEquals('image/jpeg', ExposedConverter::exposedGetMimeType(self::$imgDir . '/test.jpg'));
//$this->assertEquals('image/png', ExposedConverter::exposedGetMimeType(self::$imgDir . '/test.png'));
//$mimeTypeMaybeDetected = ExposedConverter::exposedGetMimeType(self::$imgDir . '/png-without-extension');
$successConverterJpeg = SuccessGuaranteedConverter::createInstance(
self::getImagePath('test.jpg'),
self::getImagePath('test.jpg.webp')
);
$this->assertEquals('image/jpeg', $successConverterJpeg->getMimeTypeOfSource());
$successConverterPng = SuccessGuaranteedConverter::createInstance(
self::getImagePath('test.png'),
self::getImagePath('test.png.webp')
);
$this->assertEquals('image/png', $successConverterPng->getMimeTypeOfSource());
$successConverterPngMaybeDetected = SuccessGuaranteedConverter::createInstance(
self::getImagePath('png-without-extension'),
self::getImagePath('png-without-extension.webp')
);
$mimeTypeMaybeDetected = $successConverterPngMaybeDetected->getMimeTypeOfSource();
if ($mimeTypeMaybeDetected === false) {
// It was not detected, and that is ok!
// - it is not possible to detect mime type on all platforms. In case it could not be detected,
// - and file extension could not be mapped either, the method returns false.
$this->addToAssertionCount(1);
} else {
$this->assertEquals('image/png', $mimeTypeMaybeDetected);
}
}
public function testDefaultOptions()
{
$converter = new SuccessGuaranteedConverter(
self::getImagePath('test.jpg'),
self::getImagePath('test.jpg.webp')
);
$exposer = new AbstractConverterExposer($converter);
$defaultOptions = $exposer->getOptions();
//$this->assertSame('auto', $defaultOptions['quality']);
$this->assertSame(75, $defaultOptions['quality']);
$this->assertSame(85, $defaultOptions['max-quality']);
$this->assertSame(75, $defaultOptions['default-quality']);
$this->assertSame('none', $defaultOptions['metadata']);
}
public function testOptionMerging()
{
$converter = new SuccessGuaranteedConverter(
self::getImagePath('test.jpg'),
self::getImagePath('test.webp'),
[
'quality' => 80
]
);
$exposer = new AbstractConverterExposer($converter);
//$exposer->prepareOptions();
$mergedOptions = $exposer->getOptions();
$this->assertSame(80, $mergedOptions['quality']);
}
}

View File

@@ -0,0 +1,190 @@
<?php
namespace WebPConvert\Tests\Convert\Converters\BaseTraits;
//use WebPConvert\Convert\BaseConverters\AbstractCloudConverter;
use WebPConvert\Tests\Convert\TestConverters\SuccessGuaranteedConverter;
use PHPUnit\Framework\TestCase;
class AutoQualityTraitTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testFixedQuality()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('small-q61.jpg'),
self::getImagePath('small-q61.jpg.webp'),
[
'quality' => 77,
'auto-limit' => false,
]
);
$result = $converter->getCalculatedQuality();
$this->assertSame(77, $result);
$this->assertFalse($converter->isQualityDetectionRequiredButFailing());
// Test that it is still the same (testing caching)
$this->assertFalse($converter->isQualityDetectionRequiredButFailing());
}
/*
public function testAutoQualityWhenQualityCannotBeDetected()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::$imgDir . '/non-existant',
self::$imgDir . '/non-existant.webp',
[
'max-quality' => 80,
'quality' => 'auto',
'default-quality' => 70,
]
);
$result = $converter->getCalculatedQuality();
$this->assertSame(70, $result);
}*/
public function testAutoQuality()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('small-q61.jpg'),
self::getImagePath('small-q61.jpg.webp'),
[
'quality' => 61,
'auto-limit' => true,
]
);
$result = $converter->getCalculatedQuality();
// "Cheating" a bit here...
// - If quality detection fails, it will be 61 (because default-quality is set to 61)
// - If quality detection succeeds, it will also be 61
$this->assertSame(61, $result);
}
public function testAutoQualityDeprecatedOptions()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('small-q61.jpg'),
self::getImagePath('small-q61.jpg.webp'),
[
'max-quality' => 80,
'quality' => 'auto',
'default-quality' => 61,
]
);
$result = $converter->getCalculatedQuality();
// "Cheating" a bit here...
// - If quality detection fails, it will be 61 (because default-quality is set to 61)
// - If quality detection succeeds, it will also be 61
$this->assertSame(61, $result);
}
public function testAutoQualityMaxQuality()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('small-q61.jpg'),
self::getImagePath('small-q61.jpg.webp'),
[
'max-quality' => 80,
'quality' => 'auto',
'default-quality' => 61,
]
);
//$this->assertTrue(file_exists(self::$imgDir . '/small-q61.jpg'));
//$this->assertEquals('image/jpeg', $converter->getMimeTypeOfSource());
$this->assertSame(61, $converter->getCalculatedQuality());
// Test that it is still the same (testing caching)
$this->assertSame(61, $converter->getCalculatedQuality());
}
public function testAutoQualityMaxQualityOnNonJpeg()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('test.png'),
self::getImagePath('test.png.webp'),
[
'max-quality' => 60,
'quality' => 'auto',
'default-quality' => 70,
]
);
$this->assertSame(60, $converter->getCalculatedQuality());
$this->assertFalse($converter->isQualityDetectionRequiredButFailing());
}
/*
public function testAutoQualityOnQualityDetectionFail1()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::$imgDir . '/non-existing.jpg',
self::$imgDir . '/non-existant.webp',
[
'max-quality' => 70,
'quality' => 'auto',
'default-quality' => 60,
]
);
$this->assertFalse(file_exists(self::$imgDir . '/non-existing.jpg'));
// MimeType guesser returns false when mime type cannot be established.
$this->assertEquals(false, $converter->getMimeTypeOfSource());
// - so this can actually not be used for testing isQualityDetectionRequiredButFailing
//$this->assertSame(60, $converter->getCalculatedQuality());
//$this->assertTrue($converter->isQualityDetectionRequiredButFailing());
}
*/
public function testAutoQualityOnQualityDetectionFail2DeprecatedOptions()
{
$converter = SuccessGuaranteedConverter::createInstance(
self::getImagePath('text-with-jpg-extension.jpg'),
self::getImagePath('text-with-jpg-extension.jpg.webp'),
[
'max-quality' => 70,
'quality' => 'auto',
'default-quality' => 60,
]
);
$this->assertFalse(file_exists(self::getImagePath('non-existing.jpg')));
// We are using the lenient MimeType guesser.
// So we get "image/jpeg" even though the file is not a jpeg file
$this->assertEquals('image/jpeg', $converter->getMimeTypeOfSource());
// Now we got a file that we should not be able to detect quality of
// lets validate that statement:
$this->assertTrue($converter->isQualityDetectionRequiredButFailing());
// Test that it is still the same (testing caching)
$this->assertTrue($converter->isQualityDetectionRequiredButFailing());
$this->assertSame(60, $converter->getCalculatedQuality());
}
}

View File

@@ -0,0 +1,207 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\ConverterFactory;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConversionSkippedException;
use WebPConvert\Convert\Exceptions\ConversionFailed\UnhandledException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Convert\Exceptions\ConversionFailed\FileSystemProblems\CreateDestinationFolderException;
//use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\TargetNotFoundException;
use WebPConvert\Exceptions\InvalidInput\TargetNotFoundException;
class ConverterTestHelper
{
/*
public function testPNGDeclined()
{
try {
$source = __DIR__ . '/../test.png';
$destination = __DIR__ . '/../test.png.webp';
Gd::convert($source, $destination, array(
'skip-pngs' => true,
));
$testCase->fail('The conversion should have failed, because PNG should have been skipped');
} catch (SystemRequirementsNotMetException $e) {
// System requirements are not met, so could not make the test
return;
} catch (ConversionSkippedException $e) {
// Yeah, this is what we wanted to test. And it went well!
$testCase->assertTrue(true);
} catch (ConversionFailedException $e) {
$testCase->fail("A ConversionFailedException was thrown (and it was not the SystemRequirementsNotMetException)");
} catch (\Exception $e) {
$testCase->fail("An unexpected exception was thrown");
}
}
*/
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
private static function callConvert($converterClassName, $source, $destination, $converterOptions)
{
return call_user_func(
['WebPConvert\\Convert\\Converters\\' . $converterClassName, 'convert'],
$source,
$destination,
$converterOptions
);
//$logger
/*
TODO: Consider using mikey179/vfsStream
https://github.com/mikey179/vfsStream
https://phpunit.de/manual/6.5/en/test-doubles.html#test-doubles.mocking-the-filesystem
*/
}
public static function testInvalidDestinationFolder($testCase, $converterClassName, $converterOptions)
{
$testCase->expectException(CreateDestinationFolderException::class);
try {
$source = self::getImagePath('test.jpg');
$destination = '/you-can-delete-me/';
$result = self::callConvert($converterClassName, $source, $destination);
} catch (ConverterNotOperationalException $e) {
// Converter not operational, and that is ok!
// We shall pretend that the expected exception was thrown, by throwing it!
throw new CreateDestinationFolderException();
}
/*
try {
// We can only do this test, if the converter is operational.
// In order to test that, we first do a normal conversion
$source = (__DIR__ . '/../../test.jpg');
$destination = (__DIR__ . '/../../test.webp');
Imagick::convert($source, $destination);
// if we are here, it means that the converter is operational.
// Now do something that tests that the converter fails the way it should,
// when it cannot create the destination file
$this->expectException(\WebPConvert\Convert\Exceptions\ConverterFailedException::class);
// I here assume that no system grants write access to their root folder
// this is perhaps wrong to assume?
$destinationFolder = '/you-can-delete-me/';
Imagick::convert(__DIR__ . '/../test.jpg', $destinationFolder . 'you-can-delete-me.webp');
} catch (\Exception $e) {
// its ok...
}*/
}
public static function testTargetNotFound($testCase, $converterClassName, $converterOptions)
{
$testCase->expectException(TargetNotFoundException::class);
try {
$result = self::callConvert(
$converterClassName,
__DIR__ . '/i-dont-exist.jpg',
__DIR__ . '/i-dont-exist.webp',
$converterOptions
);
} catch (ConverterNotOperationalException $e) {
// Converter not operational, and that is ok!
// We shall pretend that the expected exception was thrown, by throwing it!
throw new TargetNotFoundException();
}
}
/**
* Test convert.
* - It must either make a successful conversion, or throw the SystemRequirementsNotMetException
* Other exceptions are unexpected and will result in test failure
* - It must not return anything (as of 2.0, there is no return value)
* - If conversion is successful, there must be a file at the destination
*/
public static function testConvert($src, $testCase, $converterClassName, $converterOptions)
{
try {
$source = self::getImagePath($src);
$destination = self::getImagePath($src . '.webp');
$result = self::callConvert($converterClassName, $source, $destination, $converterOptions);
// Conversion was successful.
// make sure the function did not return anything (as of 2.0)
$testCase->assertEmpty($result, 'The doActualConvert() method returned something. As of 2.0, converters should never return anything');
// verify that there indeed is a file
$testCase->assertTrue(file_exists($destination), 'There is not a converted file at the destinaiton');
} catch (ConverterNotOperationalException $e) {
// Converter not operational, and that is ok!
// (ie if system requirements are not met, or the quota of a cloud converter is used up)
} catch (UnhandledException $e) {
// Handle the UnhandledException specially, so we can display the original error
$prevEx = $e->getPrevious();
$testCase->fail(
'An UnhandledException was thrown: ' .
get_class($prevEx). '. ' .
$prevEx->getMessage() . '. ' .
$prevEx->getFile() . ', line:' . $prevEx->getLine()
//'Trace:' . $prevEx->getTraceAsString()
);
} catch (ConversionFailedException $e) {
$testCase->fail(
"A ConversionFailedException was thrown (and it was not a ConverterNotOperationalException). The exception was: " .
get_class($e) .
". The message was: '" . $e->getMessage() . "'");
} catch (\Exception $e) {
$testCase->fail("An unexpected exception was thrown:" . get_class($e) . '. Message:' . $e->getMessage());
}
}
public static function warnIfNotOperational($converterClassName)
{
$converter = ConverterFactory::makeConverterFromClassname(
'WebPConvert\\Convert\\Converters\\' . $converterClassName,
$source = self::getImagePath('test.jpg'),
$destination = self::getImagePath('test.jpg.webp')
);
try {
$converter->checkOperationality();
//echo "\n" . $converterClassName . ' is operational.' . "\n";
} catch (\Exception $e) {
echo "\n" . 'NOTICE: ' . $converterClassName . ' is not operational: ' . $e->getMessage() . "\n";
}
}
public static function runAllConvertTests($testCase, $converterClassName, $converterOptions = [])
{
self::warnIfNotOperational($converterClassName);
$converterOptions['encoding'] = 'auto';
self::testConvert('test.jpg', $testCase, $converterClassName, $converterOptions);
self::testConvert('test.png', $testCase, $converterClassName, $converterOptions);
//self::testConvert('not-true-color.png', $testCase, $converterClassName, $converterOptions);
self::testTargetNotFound($testCase, $converterClassName, $converterOptions);
self::testInvalidDestinationFolder($testCase, $converterClassName, $converterOptions);
}
}

View File

@@ -0,0 +1,322 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Cwebp;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Tests\CompatibleTestCase;
use WebPConvert\Tests\Convert\Exposers\CwebpExposer;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass WebPConvert\Convert\Converters\Cwebp
* @covers WebPConvert\Convert\Converters\Cwebp
*/
class CwebpTest extends CompatibleTestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'Cwebp');
}
public function testSource()
{
$source = self::getImagePath('test.png');
$cwebp = new Cwebp($source, $source . '.webp');
$cwebpExposer = new CwebpExposer($cwebp);
$this->assertEquals($source, $cwebpExposer->getSource());
$this->assertTrue(file_exists($source), 'source does not exist');
}
/**
* @covers ::createCommandLineOptions
*/
public function testCreateCommandLineOptions()
{
$source = self::getImagePath('test.png');
$options = [
'quality' => 'auto',
'method' => 3,
'command-line-options' => '-sharpness 5 -crop 10 10 40 40 -low_memory',
];
$cwebp = new Cwebp($source, $source . '.webp', $options);
$cwebpExposer = new CwebpExposer($cwebp);
//$cwebpExposer->prepareOptions();
$commandLineOptions = $cwebpExposer->createCommandLineOptions();
//$this->assertEquals('e', $commandLineOption); // use this to quickly see it...
// Per default we have no preset set
$this->assertDoesNotMatchRegularExpression2('#-preset#', $commandLineOptions);
// Metadata is per default none
$this->assertMatchesRegularExpression2('#-metadata none#', $commandLineOptions);
// We passed the method option and set it to 3
$this->assertMatchesRegularExpression2('#-m 3#', $commandLineOptions);
// There must be an output option, and it must be quoted
$this->assertMatchesRegularExpression2('#-o [\'"]#', $commandLineOptions);
// There must be a quality option, and it must be digits
$this->assertMatchesRegularExpression2('#-q \\d+#', $commandLineOptions);
// -sharpness '5'
$this->assertMatchesRegularExpression2('#-sharpness [\'"]5[\'"]#', $commandLineOptions);
// Extra command line option with multiple values. Each are escapeshellarg'ed
$this->assertMatchesRegularExpression2(
'#-crop [\'"]10[\'"] [\'"]10[\'"] [\'"]40[\'"] [\'"]40[\'"]#',
$commandLineOptions
);
// Command line option (flag)
$this->assertMatchesRegularExpression2('#-low_memory#', $commandLineOptions);
// -sharpness '5'
$this->assertMatchesRegularExpression2('#-sharpness [\'"]5[\'"]#', $commandLineOptions);
}
/**
* @covers ::createCommandLineOptions
*/
public function testCreateCommandLineOptions2()
{
$source = self::getImagePath('test.png');
$options = [
'quality' => 70,
'method' => 3,
'size-in-percentage' => 55,
'preset' => 'picture'
];
$cwebp = new Cwebp($source, $source . '.webp', $options);
$cwebpExposer = new CwebpExposer($cwebp);
//$cwebpExposer->prepareOptions();
$commandLineOptions = $cwebpExposer->createCommandLineOptions();
// Preset
// Note that escapeshellarg uses doublequotes on Windows
$this->assertMatchesRegularExpression2("#-preset ['\"]picture['\"]#", $commandLineOptions);
// Size
$fileSizeInBytes = floor($options['size-in-percentage']/100 * filesize($source));
$this->assertEquals(1714, $fileSizeInBytes);
$this->assertMatchesRegularExpression2('#-size ' . $fileSizeInBytes . '#', $commandLineOptions);
// There must be no quality option, because -size overrules it.
$this->assertDoesNotMatchRegularExpression2('#-q \\d+#', $commandLineOptions);
}
/**
* @covers ::createCommandLineOptions
*/
public function testCreateCommandLineOptions3()
{
$source = self::getImagePath('test.png');
$options = [
'encoding' => 'lossless',
'near-lossless' => 75,
'auto-filter' => true,
];
$cwebp = new Cwebp($source, $source . '.webp', $options);
$cwebpExposer = new CwebpExposer($cwebp);
$commandLineOptions = $cwebpExposer->createCommandLineOptions();
// near-lossless
$this->assertMatchesRegularExpression2('#-near_lossless 75#', $commandLineOptions);
// There must be no -lossless option, because -near-lossless overrules it.
$this->assertDoesNotMatchRegularExpression2('#-lossless#', $commandLineOptions);
// auto-filter
$this->assertMatchesRegularExpression2('#-af#', $commandLineOptions);
// no low-memory
$this->assertDoesNotMatchRegularExpression2('#-low_memory#', $commandLineOptions);
}
/**
* @covers ::createCommandLineOptions
*/
public function testCreateCommandLineOptions4()
{
$source = self::getImagePath('test.png');
$options = [
'encoding' => 'lossless',
'near-lossless' => 100,
'low-memory' => true,
];
$cwebp = new Cwebp($source, $source . '.webp', $options);
$cwebpExposer = new CwebpExposer($cwebp);
$commandLineOptions = $cwebpExposer->createCommandLineOptions();
// lossless
$this->assertMatchesRegularExpression2('#-lossless#', $commandLineOptions);
// There must be no -near_lossless option, because -lossless overrules it.
$this->assertDoesNotMatchRegularExpression2('#-near_lossless#', $commandLineOptions);
// low-memory
$this->assertMatchesRegularExpression2('#-low_memory#', $commandLineOptions);
// No auto-filter
$this->assertDoesNotMatchRegularExpression2('#-af#', $commandLineOptions);
}
/**
* @covers ::checkOperationality
*/
public function testOperatinalityException()
{
$source = self::getImagePath('test.png');
$options = [
'try-cwebp' => false,
'try-supplied-binary-for-os' => false,
'try-common-system-paths' => false,
'try-discovering-cwebp' => false,
];
$this->expectException(ConverterNotOperationalException::class);
//$cwebp = new Cwebp($source, $source . '.webp', $options);
Cwebp::convert($source, $source . '.webp', $options);
}
public function testUsingSuppliedBinaryForOS()
{
$source = self::getImagePath('test.png');
$options = [
'try-cwebp' => false,
'try-supplied-binary-for-os' => true,
'try-common-system-paths' => false,
'try-discovering-cwebp' => false,
];
//$this->expectException(ConverterNotOperationalException::class);
//$cwebp = new Cwebp($source, $source . '.webp', $options);
try {
Cwebp::convert($source, $source . '.webp', $options);
} catch (ConversionFailedException $e) {
// this is ok.
// - but other exceptions are not!
}
$this->addToAssertionCount(1);
}
public function testUsingCommonSystemPaths()
{
$source = self::getImagePath('test.png');
$options = [
'try-cwebp' => false,
'try-supplied-binary-for-os' => false,
'try-common-system-paths' => true,
'try-discovering-cwebp' => false,
];
//$this->expectException(ConverterNotOperationalException::class);
//$cwebp = new Cwebp($source, $source . '.webp', $options);
try {
Cwebp::convert($source, $source . '.webp', $options);
} catch (ConversionFailedException $e) {
// this is ok.
// - but other exceptions are not!
}
$this->addToAssertionCount(1);
}
/*
public function testCwebpDefaultPaths()
{
$default = [
'/usr/bin/cwebp',
'/usr/local/bin/cwebp',
'/usr/gnu/bin/cwebp',
'/usr/syno/bin/cwebp'
];
foreach ($default as $key) {
$this->assertContains($key, Cwebp::$cwebpDefaultPaths);
}
}*/
/**
* @expectedException \Exception
*/
/*
public function testUpdateBinariesInvalidFile()
{
$array = [];
Cwebp::updateBinaries('InvalidFile', 'Hash', $array);
}*/
/**
* @expectedException \Exception
*/
/*
public function testUpdateBinariesInvalidHash()
{
$array = [];
Cwebp::updateBinaries('cwebp-linux', 'InvalidHash', $array);
}
public function testUpdateBinaries()
{
$file = 'cwebp.exe';
$filePath = realpath(__DIR__ . '/../../Converters/Binaries/' . $file);
$hash = hash_file('sha256', $filePath);
$array = [];
$this->assertContains($filePath, Cwebp::updateBinaries($file, $hash, $array));
}
public function testEscapeFilename()
{
$wrong = '/path/to/file Na<>me."ext"';
$right = '/path/to/file\\\ Name.\&#34;ext\&#34;';
$this->assertEquals($right, Cwebp::escapeFilename($wrong));
}
public function testHasNiceSupport()
{
$this->assertNotNull(Cwebp::hasNiceSupport());
}*/
/*
public function testConvert()
{
$source = realpath(__DIR__ . '/../test.jpg');
$destination = realpath(__DIR__ . '/../test.webp');
$quality = 85;
$stripMetadata = true;
$this->assertTrue(Cwebp::convert($source, $destination, $quality, $stripMetadata));
}*/
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Ewww;
use PHPUnit\Framework\TestCase;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\InvalidApiKeyException;
use WebPConvert\Tests\Convert\TestConverters\ExtendedConverters\EwwwExtended;
class EwwwTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'Ewww', [
//'api-key' => ''
]);
}
public function testConvertInvalidKeyLessThan20()
{
$this->expectException(InvalidApiKeyException::class);
$source = self::getImagePath('test.png');
Ewww::convert($source, $source . '.webp', [
'api-key' => 'wrong-key!'
]);
}
public function testConvertInvalidKeyLess32()
{
$this->expectException(InvalidApiKeyException::class);
$wrongKeyRightLength = 'invalid-key-but-hasright-length';
$source = self::getImagePath('test.png');
Ewww::convert($source, $source . '.webp', [
'api-key' => $wrongKeyRightLength
]);
}
public function testConvertInvalidKeyDuringConversion()
{
$this->expectException(InvalidApiKeyException::class);
$wrongKeyRightLength = 'invalid-key-but-hasright-length';
$source = self::getImagePath('test.png');
$ee = EwwwExtended::createInstance($source, $source . '.webp', [
'api-key' => $wrongKeyRightLength
]);
$ee->callDoActualConvert();
}
public function testIsValidKey()
{
$invalidKey = 'notvalidno';
$this->assertFalse(Ewww::isValidKey($invalidKey));
$demoKey = 'abc123';
$this->assertTrue(Ewww::isValidKey($demoKey));
//InvalidApiKeyException
}
public function testIsWorkingKey()
{
$invalidKey = 'notvalidno';
$this->assertFalse(Ewww::isWorkingKey($invalidKey));
if (!empty(getenv('WEBPCONVERT_EWWW_API_KEY'))) {
$realWorkingKey = getenv('WEBPCONVERT_EWWW_API_KEY');
$this->assertTrue(Ewww::isWorkingKey($realWorkingKey));
}
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\FFMpeg;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Loggers\BufferLogger;
use PHPUnit\Framework\TestCase;
class FFMpegTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'FFMpeg');
}
/**
* Try converting.
* It is ok if converter is not operational.
* It is not ok if converter thinks it is operational, but fails
*
* @return $ok
* @throws ConversionFailedException if convert throws it
*/
private static function tryThis($test, $source, $options)
{
$bufferLogger = new BufferLogger();
try {
FFMpeg::convert($source, $source . '.webp', $options, $bufferLogger);
} catch (ConversionFailedException $e) {
// this is not ok
//$bufferLogger->getText()
throw $e;
} catch (ConverterNotOperationalException $e) {
// (SystemRequirementsNotMetException is also a ConverterNotOperationalException)
// this is ok.
return true;
}
return true;
}
public function testWithNice() {
$source = self::getImagePath('test.png');
$options = [
'use-nice' => true,
'encoding' => 'lossless',
];
$this->assertTrue(self::tryThis($this, $source, $options));
}
}

View File

@@ -0,0 +1,286 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Tests\Convert\Exposers\GdExposer;
use WebPConvert\Convert\Converters\Gd;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use PHPUnit\Framework\TestCase;
class GdTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'Gd');
}
private function createGd($src)
{
$source = self::getImagePath($src);
$this->assertTrue(file_exists($source), 'source does not exist:' . $source);
return new Gd($source, $source . '.webp');
}
private function createGdExposer($src)
{
$gd = $this->createGd($src);
return new GdExposer($gd);
}
private static function resetPretending()
{
reset_pretending();
}
// pretend imagewebp is missing
public function testNotOperational1()
{
global $pretend;
$gd = $this->createGd('test.png');
self::resetPretending();
$pretend['functionsNotExisting'] = ['imagewebp'];
$this->expectException(SystemRequirementsNotMetException::class);
$gd->checkOperationality();
}
// pretend gd is not loaded
public function testNotOperational2()
{
global $pretend;
$gd = $this->createGd('test.png');
self::resetPretending();
$pretend['extensionsNotExisting'] = ['gd'];
$this->expectException(SystemRequirementsNotMetException::class);
$gd->checkOperationality();
$pretend['extensionsNotExisting'] = [];
}
// pretend imagecreatefrompng is missing
public function testCheckConvertability1()
{
global $pretend;
$gd = $this->createGd('test.png');
self::resetPretending();
$pretend['functionsNotExisting'] = ['imagecreatefrompng'];
$this->expectException(SystemRequirementsNotMetException::class);
$gd->checkConvertability();
$pretend['functionsNotExisting'] = [];
}
// pretend imagecreatefrompng is working
public function testCheckConvertability2()
{
global $pretend;
$gd = $this->createGd('test.png');
self::resetPretending();
$pretend['functionsExisting'] = ['imagecreatefrompng'];
$gd->checkConvertability();
$pretend['functionsExisting'] = [];
}
// pretend imagecreatefromjpeg is missing
public function testCheckConvertability3()
{
global $pretend;
$gd = $this->createGd('test.jpg');
self::resetPretending();
$pretend['functionsNotExisting'] = ['imagecreatefromjpeg'];
$this->expectException(SystemRequirementsNotMetException::class);
$gd->checkConvertability();
$pretend['functionsNotExisting'] = [];
}
public function testSource()
{
$source = self::getImagePath('test.png');
$gd = new Gd($source, $source . '.webp');
self::resetPretending();
$gdExposer = new GdExposer($gd);
$this->assertEquals($source, $gdExposer->getSource());
$this->assertTrue(file_exists($source), 'source does not exist');
}
public function testCreateImageResource()
{
$gd = $this->createGd('test.png');
self::resetPretending();
$gdExposer = new GdExposer($gd);
if (!$gdExposer->isOperating()) {
//$this->assertTrue(false);
return;
}
// It is operating and image should be ok.
// - so it should be able to create image resource (or, for PHP 8, an \GdImage object)
$image = $gdExposer->createImageResource();
$isResourceOrObject = ((gettype($image) == 'resource') || (gettype($image) == 'object'));
$this->assertTrue($isResourceOrObject, 'Expected createImageResource to return a resource or an object but got:' . gettype($image));
/*
// Try the workaround method.
$result = $gdExposer->makeTrueColorUsingWorkaround($image);
// As the workaround is pretty sturdy, let us assert that it simply works.
// It would be good to find out if it doesn't, anyway!
$this->assertTrue($result); */
//$gdExposer->tryToMakeTrueColorIfNot($image);
$this->assertTrue(imageistruecolor($image), 'image is not true color');
$result = $gdExposer->trySettingAlphaBlending($image);
$this->assertTrue($result, 'failed setting alpha blending');
}
public function testStuffOnNotTrueColor()
{
$gd = $this->createGd('not-true-color.png');
self::resetPretending();
$gdExposer = new GdExposer($gd);
if (!$gdExposer->isOperating()) {
return;
}
// It is operating and image should be ok.
// - so it should be able to create image resource
$image = $gdExposer->createImageResource();
$isResourceOrObject = ((gettype($image) == 'resource') || (gettype($image) == 'object'));
$this->assertTrue($isResourceOrObject, 'Expected createImageResource to return a resource or an object but got:' . gettype($image));
$this->assertFalse(imageistruecolor($image), 'image is already true color');
$gdExposer->tryToMakeTrueColorIfNot($image);
$this->assertTrue(imageistruecolor($image), 'image is not true color after trying to make it');
$result = $gdExposer->trySettingAlphaBlending($image);
$this->assertTrue($result, 'failed setting alpha blending');
// Test the workaround method.
$gd = $this->createGd('not-true-color.png');
$gdExposer = new GdExposer($gd);
$image = $gdExposer->createImageResource();
$this->assertFalse(imageistruecolor($image), 'image is already true color');
//$image = imagecreatetruecolor(imagesx($image), imagesy($image));
$result = $gdExposer->makeTrueColorUsingWorkaround($image);
//$result = $gd->makeTrueColorUsingWorkaround($image);
$this->assertTrue($result);
$this->assertTrue(imageistruecolor($image), 'image is not true color after trying to make it (with workaround method)');
$result = $gdExposer->trySettingAlphaBlending($image);
$this->assertTrue($result, 'failed setting alpha blending');
}
public function testConvertFailure()
{
echo 'OS: ' . PHP_OS;
$gdExposer = $this->createGdExposer('not-true-color.png');
self::resetPretending();
// The next requires imagewebp...
if (!function_exists('imagewebp')) {
return;
}
$image = $gdExposer->createImageResource();
// This image is not true color.
// Trying to convert it fails (empty string is generated)
// Assert that I am right!
// In most cases the following triggers a warning:
// Warning: imagewebp(): Palette image not supported by webp in /var/www/wc/wc0/webp-convert/tests/Convert/Converters/GdTest.php on line 215
//
// However, in Windows-2022 (PHP 8), it throws A FATAL!
// Error: PHP Fatal error: Paletter image not supported by webp in D:\a\webp-convert\webp-convert\tests\Convert\Converters\GdTest.php on line 222
//
// And its worse and Mac (PHP 7.1 and 7.3, not 7.4 and 8.0)
// It just halts execution - see ##322
//
// In Ubuntu, PHP 8.1 it throws fatal too. I think this behaviour starts from PHP 8.0.0.
$isWindows = preg_match('/^win/i', PHP_OS);
$isMacDarwin = preg_match('/^darwin/i', PHP_OS);
$isPHP8orAbove = (version_compare(PHP_VERSION, '8.0.0') >= 0);
if (!$isWindows && !$isMacDarwin && !$isPHP8orAbove) {
ob_start();
try {
@imagewebp($image, null, 80);
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
$output = ob_get_clean();
// The failure results in no output:
$this->assertEquals($output, '');
// similary, we should get an exception when calling tryConverting ('Gd failed: imagewebp() returned empty string')
//$this->expectException(ConversionFailedException::class);
$gotExpectedException = false;
try {
$gdExposer->tryConverting($image);
} catch (ConversionFailedException $e) {
$gotExpectedException = true;
}
$this->assertTrue(
$gotExpectedException,
'did not get expected exception when converting palette image with Gd, ' .
'bypassing the code that converts to true color'
);
}
//$gdExposer->tryToMakeTrueColorIfNot($image);
//$pretend['functionsNotExisting'] = ['imagewebp'];
}
/*
public function testMakeTrueColorUsingWorkaround()
{
$gd = $this->createGd('test.png');
self::resetPretending();
$gdExposer = new GdExposer($gd);
if (!$gdExposer->isOperating()) {
return;
}
}*/
}
require_once('pretend.inc');

View File

@@ -0,0 +1,29 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use PHPUnit\Framework\TestCase;
class GmagickTest extends TestCase
{
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'Gmagick');
}
/*
public function testSupported()
{
if (!extension_loaded('Gmagick')) {
return;
}
if (!class_exists('Gmagick')) {
return;
}
$im = new \Gmagick();
$this->assertSame([], $im->queryformats());
}
*/
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\GraphicsMagick;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Loggers\BufferLogger;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass WebPConvert\Convert\Converters\GraphicsMagick
* @covers WebPConvert\Convert\Converters\GraphicsMagick
*/
class GraphicsMagickTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'GraphicsMagick');
}
/**
* Try converting.
* It is ok if converter is not operational.
* It is not ok if converter thinks it is operational, but fails
*
* @return $ok
* @throws ConversionFailedException if convert throws it
*/
private static function tryThis($test, $source, $options)
{
$bufferLogger = new BufferLogger();
try {
GraphicsMagick::convert($source, $source . '.webp', $options, $bufferLogger);
} catch (ConversionFailedException $e) {
//$bufferLogger->getText()
throw $e;
} catch (ConverterNotOperationalException $e) {
// (SystemRequirementsNotMetException is also a ConverterNotOperationalException)
// this is ok.
return true;
}
return true;
}
public function testWithNice() {
$source = self::getImagePath('test.png');
$options = [
'use-nice' => true,
'lossless' => true,
];
$this->assertTrue(self::tryThis($this, $source, $options));
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\ImageMagick;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Loggers\BufferLogger;
use PHPUnit\Framework\TestCase;
class ImageMagickTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'ImageMagick');
}
private static function tryThis($test, $source, $options)
{
$bufferLogger = new BufferLogger();
try {
ImageMagick::convert($source, $source . '.webp', $options, $bufferLogger);
$test->addToAssertionCount(1);
} catch (ConversionFailedException $e) {
//$bufferLogger->getText()
throw $e;
} catch (ConverterNotOperationalException $e) {
// (SystemRequirementsNotMetException is also a ConverterNotOperationalException)
// this is ok.
return;
}
}
public function testWithNice() {
$source = self::getImagePath('test.png');
$options = [
'use-nice' => true,
'encoding' => 'lossless',
];
self::tryThis($this, $source, $options);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Imagick;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass WebPConvert\Convert\Converters\Imagick
* @covers WebPConvert\Convert\Converters\Imagick
*/
class ImagickTest extends TestCase
{
public static $imageDir = __DIR__ . '/../../images/';
public function testConvert()
{
ConverterTestHelper::runAllConvertTests($this, 'Imagick');
}
/**
* @coversNothing
*/
public function testQueryFormats()
{
if (!extension_loaded('imagick')) {
$this->markTestSkipped(
'The imagick extension is not available.'
);
return;
}
//if (!class_exists('\\Imagick')) {}
$im = new \Imagick();
$this->assertEquals(1, count($im->queryFormats('JPEG')));
$this->assertGreaterThan(2, count($im->queryFormats('*')));
$this->assertGreaterThan(2, count($im->queryFormats()));
$this->assertEquals(count($im->queryFormats('*')), count($im->queryFormats()));
}
/**
* @coversNothing
*/
public function testThatImagickFunctionsUsedDoesNotThrow()
{
if (!extension_loaded('imagick')) {
$this->markTestSkipped(
'The imagick extension is not available.'
);
return;
}
$im = new \Imagick(self::$imageDir . '/test.jpg');
$im->setImageFormat('JPEG');
$im->stripImage();
$im->setImageCompressionQuality(100);
$imageBlob = $im->getImageBlob();
$this->addToAssertionCount(1);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Stack;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\ConverterNotFoundException;
use PHPUnit\Framework\TestCase;
class StackTest extends TestCase
{
public static function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public static function getImagePath($image)
{
return self::getImageFolder() . '/' . $image;
}
/*
public function testConvert()
{
//ConverterTestHelper::runAllConvertTests($this, 'Stack');
}*/
public function testConverterNotFound()
{
$this->expectException(ConverterNotFoundException::class);
Stack::convert(
self::getImagePath('test.jpg'),
self::getImagePath('test.webp'),
[
'converters' => ['invalid-id']
]
);
}
public function testCustomConverter()
{
Stack::convert(
self::getImagePath('test.jpg'),
self::getImagePath('test.webp'),
[
'converters' => [
'\\WebPConvert\\Tests\\Convert\\TestConverters\\SuccessGuaranteedConverter'
]
]
);
$this->addToAssertionCount(1);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Tests\Convert\Exposers\GdExposer;
use WebPConvert\Convert\Converters\Gd;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use PHPUnit\Framework\TestCase;
class TestTest extends TestCase
{
public function testTesting()
{
$this->assertEquals(
'1',
'1'
);
}
}
require_once('pretend.inc');

View File

@@ -0,0 +1,258 @@
<?php
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Vips;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use WebPConvert\Exceptions\InvalidInput\TargetNotFoundException;
use WebPConvert\Tests\Convert\Exposers\VipsExposer;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass WebPConvert\Convert\Converters\Vips
* @covers WebPConvert\Convert\Converters\Vips
*/
class VipsTest extends TestCase
{
public function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public function getImagePath($image)
{
return $this->getImageFolder() . '/' . $image;
}
public function testConvert()
{
$options = [];
ConverterTestHelper::runAllConvertTests($this, 'Vips', $options);
$options = [
'smart-subsample' => true,
'preset' => 'text',
];
ConverterTestHelper::runAllConvertTests($this, 'Vips', $options);
}
private function createVips($src, $options = [])
{
$source = $this->getImagePath($src);
$this->assertTrue(file_exists($source), 'source does not exist:' . $source);
return new Vips($source, $source . '.webp', $options);
}
private function createVipsExposer($src, $options = [])
{
return new VipsExposer($this->createVips($src, $options));
}
private function isVipsOperational()
{
try {
$vips = $this->createVips('test.png');
$vips->checkOperationality();
$vips->checkConvertability();
} catch (\Exception $e) {
return false;
}
return true;
}
public function testCreateParamsForVipsWebPSave1()
{
$options = [
'method' => 3,
'encoding' => 'lossless',
'smart-subsample' => true, // note: deprecated
'near-lossless' => 90,
'preset' => 'picture', // In vips, this has the constant: 1
];
$vipsExposer = $this->createVipsExposer('test.png', $options);
$vipsParams = $vipsExposer->createParamsForVipsWebPSave();
// Check some options that are straightforwardly copied
$this->assertSame($options['method'], $vipsParams['reduction_effort']);
$this->assertSame(true, $vipsParams['lossless']);
$this->assertSame($options['smart-subsample'], $vipsParams['smart_subsample']);
$this->assertSame(1, $vipsParams['preset']);
// When near-lossless is set, the value should be copied to Q
$this->assertSame($options['near-lossless'], $vipsParams['Q']);
}
public function testCreateParamsForVipsWebPSave2()
{
$options = [
'alpha-quality' => 100,
'sharp-yuv' => true,
];
$vipsExposer = $this->createVipsExposer('test.png', $options);
$vipsParams = $vipsExposer->createParamsForVipsWebPSave();
$this->assertSame($options['sharp-yuv'], isset($vipsParams['smart_subsample']));
// Some options are only set if they differ from default
$this->assertFalse(isset($vipsParams['alpha_q']));
}
public function testCreateImageResource1()
{
$source = $this->getImagePath('non-existing');
// Next must fail with a TargetNotFoundException
$this->expectException(TargetNotFoundException::class);
$vips = new Vips($source, $source . '.webp', []);
// Exit if vips is not operational
if (!$this->isVipsOperational()) {
return;
}
/*
$vipsExposer = new VipsExposer($vips);
// It must fail because it should not be able to create resource when file does not exist
$this->expectException(ConversionFailedException::class);
$vipsExposer->createImageResource();*/
}
public function testNotOperational1()
{
global $pretend;
$vips = $this->createVips('test.png');
reset_pretending();
// pretend vips_image_new_from_file
$pretend['functionsNotExisting'] = ['vips_image_new_from_file'];
$this->expectException(SystemRequirementsNotMetException::class);
$vips->checkOperationality();
}
public function testNotOperational2()
{
global $pretend;
$vips = $this->createVips('test.png');
reset_pretending();
// pretend vips_image_new_from_file
$pretend['extensionsNotExisting'] = ['vips'];
$this->expectException(SystemRequirementsNotMetException::class);
$vips->checkOperationality();
}
/*
Commented out because it is no good anymore, after the checkOperationality actually
itself relies on the function_exists, because it now calls "vips_call" in order to
detect if webp is supported
public function testOperational1()
{
global $pretend;
$vips = $this->createVips('test.png');
reset_pretending();
// pretend vips_image_new_from_file
$pretend['functionsExisting'] = ['vips_image_new_from_file', 'vips_call', 'vips_error_buffer'];
$pretend['extensionsExisting'] = ['vips'];
$vips->checkOperationality();
$this->addToAssertionCount(1);
}
*/
/**
* @covers ::webpsave
*/
public function testWebpsave()
{
reset_pretending();
$vips = $this->createVips('test.png', []);
$vipsExposer = new VipsExposer($vips);
// Exit if vips is not operational
if (!$this->isVipsOperational()) {
$this->markTestSkipped('vips is not operational');
return;
}
$im = $vipsExposer->createImageResource();
$options = $vipsExposer->createParamsForVipsWebPSave();
// Create non-existing vips option.
// - The converter must be able to ignore this without failing
$options['non-existing-vips-option'] = true;
$vipsExposer->webpsave($im, $options);
}
/**
* @covers ::createImageResource
*/
public function testCreateImageResourceWhenFileNotFound()
{
//
reset_pretending();
$source = $this->getImagePath('i-do-not-exist.jpg');
$this->assertFalse(file_exists($source));
$options = [];
// Next must fail with a TargetNotFoundException
$this->expectException(TargetNotFoundException::class);
$vips = new Vips($source, $source . '.webp', $options);
// Exit if vips is not operational
/*
if (!$this->isVipsOperational()) {
$this->markTestSkipped('vips is not operational');
return;
}*/
/*
$vipsExposer = new VipsExposer($vips);
// this should fail!
try {
$im = $vipsExposer->createImageResource();
$this->fail('exception was expected');
} catch (ConversionFailedException $e) {
$this->assertRegExp('#not found#', $e->getMessage());
}*/
}
/*
public function testDoActualConvert()
{
$options = [
'alpha-quality' => 100
];
$vipsExposer = $this->createVipsExposer('test.png', $options);
$vips = $this->createVips('not-existing.png');
$this->addToAssertionCount(1);
}*/
}
require_once('pretend.inc');

View File

@@ -0,0 +1,297 @@
<?php
/**
* WebPConvert - Convert JPEG & PNG to WebP with PHP
*
* @link https://github.com/rosell-dk/webp-convert
* @license MIT
*/
namespace WebPConvert\Tests\Convert\Converters;
use WebPConvert\Convert\Converters\Wpc;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperationalException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\SystemRequirementsNotMetException;
use WebPConvert\Convert\Exceptions\ConversionFailed\ConverterNotOperational\InvalidApiKeyException;
use WebPConvert\Loggers\BufferLogger;
use WebPConvert\Tests\CompatibleTestCase;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass WebPConvert\Convert\Converters\Wpc
* @covers WebPConvert\Convert\Converters\Wpc
*/
class WPCTest extends CompatibleTestCase
{
public function getImageFolder()
{
return realpath(__DIR__ . '/../../images');
}
public function getImagePath($image)
{
return $this->getImageFolder() . '/' . $image;
}
/* public function testApi0()
{
if (!empty(getenv('WEBPCONVERT_WPC_API_URL_API0'))) {
$source = $this->imageDir . '/test.png';
Wpc::convert($source, $source . '.webp', [
'api-version' => 0,
'api-url' => getenv('WEBPCONVERT_WPC_API_URL_API0')
]);
}
}
*/
private static function tryThis($test, $source, $options)
{
$bufferLogger = new BufferLogger();
try {
Wpc::convert($source, $source . '.webp', $options, $bufferLogger);
} catch (ConversionFailedException $e) {
// we accept this failure that seems to happen when WPC gets stressed:
if (strpos($e->getMessage(), 'unable to open image') !== false) {
return true;
}
// we also accept this failure that also seems to happen when WPC gets stressed:
if (strpos($e->getMessage(), 'We got nothing back') !== false) {
return true;
}
if ($e->getMessage() == 'Error saving file. Check file permissions') {
throw new ConversionFailedException(
'Failed saving file. Here is the log:' . $bufferLogger->getText()
);
}
throw $e;
}
return true;
}
public function testWarnIfNotOperational()
{
ConverterTestHelper::warnIfNotOperational('Wpc');
$this->addToAssertionCount(1);
}
public function testApi0()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL'))) {
echo "\n" . 'NOTICE: WPC is not operational. It needs api-key and api-url. ';
echo 'You can set this up by setting environment varibles WEBPCONVERT_WPC_API_URL_API and WEBPCONVERT_WPC_API_KEY. ';
echo 'To also test old api=0, use WEBPCONVERT_WPC_API_URL_API0.';
echo "\n";
} else {
if (empty(getenv('WEBPCONVERT_WPC_API_URL_API0'))) {
echo "\n" . 'NOTICE: WPC is not tested with api-version=0. To test this, you must set environment varibles WEBPCONVERT_WPC_API_URL_API0 and WEBPCONVERT_WPC_API_KEY' . "\n";
}
}
if (empty(getenv('WEBPCONVERT_WPC_API_URL_API0'))) {
$this->addToAssertionCount(1);
return;
}
$source = $this->getImagePath('test.png');
$options = [
'api-version' => 0,
'api-url' => getenv('WEBPCONVERT_WPC_API_URL_API0'),
'lossless' => true,
];
$this->assertTrue(self::tryThis($this, $source, $options));
}
public function testApi1()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL'))) {
$this->addToAssertionCount(1);
return;
}
$source = $this->getImagePath('test.png');
$options = [
'api-version' => 1,
'crypt-api-key-in-transfer' => true,
'lossless' => true,
];
$this->assertTrue(self::tryThis($this, $source, $options));
}
public function testApi2()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL'))) {
$this->addToAssertionCount(1);
return;
}
$source = $this->getImagePath('test.png');
$options = [
'api-version' => 2,
'crypt-api-key-in-transfer' => true,
'lossless' => true,
];
$this->assertTrue(self::tryThis($this, $source, $options));
}
public function testWrongSecretButRightUrl()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL'))) {
return;
}
$source = $this->getImagePath('test.png');
$options = [
'api-version' => 1,
'crypt-api-key-in-transfer' => true,
'api-key' => 'wrong!',
];
$this->expectException(InvalidApiKeyException::class);
$this->assertTrue(self::tryThis($this, $source, $options));
}
public function testBadURL()
{
$this->expectException(ConverterNotOperationalException::class);
Wpc::convert(
$this->getImagePath('test.png'),
$this->getImagePath('test.webp'),
[
'api-url' => 'badurl!',
'secret' => 'bad dog!',
]
);
}
public function test404()
{
//$this->expectException(ConversionFailedException::class);
try {
Wpc::convert(
$this->getImagePath('test.png'),
$this->getImagePath('test.webp'),
[
'api-url' => 'https://google.com/hello',
'secret' => 'bad dog!',
]
);
$this->fail('Expected an exception');
} catch (ConversionFailedException $e) {
// this is expected!
$this->addToAssertionCount(1);
$this->assertMatchesRegularExpression2('#we got a 404 response#', $e->getMessage());
}
}
public function testUnexpectedResponse()
{
//$this->expectException(ConversionFailedException::class);
try {
Wpc::convert(
$this->getImagePath('test.png'),
$this->getImagePath('test.webp'),
[
'api-url' => 'https://www.google.com/',
'secret' => 'bad dog!',
]
);
$this->fail('Expected an exception');
} catch (ConversionFailedException $e) {
// this is expected!
$this->addToAssertionCount(1);
$this->assertMatchesRegularExpression2('#We did not receive an image#', $e->getMessage());
}
}
/*
HMM.. Apparently wpc can't handle much stress.
The runAllConvertTests often results in an error like this:
'WPC failed converting image: "unable to open image '../conversions/80c80b20834edd62456fe9e6da4d24d64be51dc1.jpg': No such file or directory @ error/blob.c/OpenBlob/3489"'
public function testApi0()
{
if (!empty(getenv('WEBPCONVERT_WPC_API_URL_API0'))) {
ConverterTestHelper::runAllConvertTests($this, 'Wpc', [
'api-version' => 0,
'api-url' => getenv('WEBPCONVERT_WPC_API_URL_API0')
]);
}
}
public function testApi1()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL')) || empty(getenv('WEBPCONVERT_WPC_API_KEY'))) {
return;
}
ConverterTestHelper::runAllConvertTests($this, 'Wpc', [
'api-version' => 1,
'crypt-api-key-in-transfer' => true
]);
// TODO: Also test without crypt
}
*/
/*
public function testMissingURL()
{
$this->expectException(ConverterNotOperationalException::class);
Wpc::convert($this->imageDir . '/test.png', $this->imageDir . '/test.webp', [
'api-url' => '',
'secret' => 'bad dog!',
]);
}*/
/*
public function testWrongSecretButRightUrl()
{
if (empty(getenv('WEBPCONVERT_WPC_API_URL'))) {
return;
}
$this->expectException(InvalidApiKeyException::class);
Wpc::convert($this->imageDir . '/test.png', $this->imageDir . '/test.webp', [
'api-version' => 0,
'api-url' => getenv('WEBPCONVERT_WPC_API_URL'),
'secret' => 'purposely-wrong-secret!'
]);
}
public function testBadURL()
{
$this->expectException(ConverterNotOperationalException::class);
Wpc::convert($this->imageDir . '/test.png', $this->imageDir . '/test.webp', [
'api-url' => 'badurl!',
'secret' => 'bad dog!',
]);
}*/
}

View File

@@ -0,0 +1,55 @@
<?php
namespace {
$pretend = [
'functionsNotExisting' => [],
'functionsExisting' => [],
'extensionsNotExisting' => [],
'extensionsExisting' => []
];
$hasDeclaredMockFunctions = false;
function reset_pretending()
{
global $pretend;
$pretend = [
'functionsNotExisting' => [],
'functionsExisting' => [],
'extensionsNotExisting' => [],
'extensionsExisting' => []
];
}
}
namespace WebPConvert\Convert\Converters {
global $hasDeclaredMockFunctions;
if(!$hasDeclaredMockFunctions) {
$hasDeclaredMockFunctions = true;
function function_exists($function) {
global $pretend;
if (in_array($function, $pretend['functionsNotExisting'])) {
return false;
}
if (in_array($function, $pretend['functionsExisting'])) {
return true;
}
return \function_exists($function);
}
function extension_loaded($extension) {
global $pretend;
if (in_array($extension, $pretend['extensionsNotExisting'])) {
return false;
}
if (in_array($extension, $pretend['extensionsExisting'])) {
return true;
}
return \extension_loaded($extension);
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace WebPConvert\Tests\Convert\Exposers;
use WebPConvert\Convert\Converters\AbstractConverter;
use WebPConvert\Tests\BaseExposer;
/**
* Class for exposing otherwise unaccessible methods of AbstractConverter,
* - so they can be tested
*
* TODO: expose and test more methods! (and make more methods private/protected in AbstractConverter)
*/
class AbstractConverterExposer extends BaseExposer {
//public static $extraOptions = [];
public $converter;
public static $currentlyCalling;
public function __construct($converter)
{
parent::__construct($converter);
}
public function getSource()
{
return $this->getPrivateProperty('source');
}
public function isOperating()
{
$inject = function() {
try {
$this->checkOperationality();
$this->checkConvertability();
} catch (\Exception $e) {
return false;
}
return true;
};
return $this->bindDynamicFunctionToObjectAndCallIt($inject);
}
/*
public function prepareOptions()
{
$this->callPrivateFunction('prepareOptions', AbstractConverter::class);
}*/
public function getOptions()
{
return $this->getPrivateProperty('options', AbstractConverter::class);
}
/*
public function getDefaultOptions()
{
//return $this->getPrivateStaticProperty('defaultOptions', AbstractConverter::class);
return $this->callPrivateFunction('getDefaultOptions', AbstractConverter::class);
}*/
}

View File

@@ -0,0 +1,23 @@
<?php
namespace WebPConvert\Tests\Convert\Exposers;
/**
* Class for exposing otherwise unaccessible methods of AbstractConverter,
* - so they can be tested
*
* TODO: expose and test more methods! (and make more methods private/protected in AbstractConverter)
*/
class CwebpExposer extends AbstractConverterExposer {
public function __construct($gd)
{
parent::__construct($gd);
}
public function createCommandLineOptions($version = '0.6.1')
{
return $this->callPrivateFunction('createCommandLineOptions', null, $version);
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace WebPConvert\Tests\Convert\Exposers;
use WebPConvert\Convert\Converters\Gd;
/**
* Class for exposing otherwise unaccessible methods of AbstractConverter,
* - so they can be tested
*
* TODO: expose and test more methods! (and make more methods private/protected in AbstractConverter)
*/
class GdExposer extends AbstractConverterExposer {
public function __construct($gd)
{
parent::__construct($gd);
}
public function createImageResource()
{
return $this->callPrivateFunction('createImageResource', null);
}
public function makeTrueColorUsingWorkaround(&$image)
{
return $this->callPrivateFunctionByRef('makeTrueColorUsingWorkaround', $image);
// return $this->callPrivateFunction('makeTrueColorUsingWorkaround', null, $image);
/*
The following would also work:
$cb = function(&$image) {
echo 'callback:...' . gettype($image);
return $this->makeTrueColorUsingWorkaround($image);
};
//$class = get_class(Gd::class);
$functionNowBinded = $cb->bindTo($this->objectToExposeFrom, Gd::class);
return $functionNowBinded($image);*/
}
public function trySettingAlphaBlending(&$image)
{
return $this->callPrivateFunctionByRef('trySettingAlphaBlending', $image);
}
public function tryToMakeTrueColorIfNot(&$image)
{
return $this->callPrivateFunctionByRef('tryToMakeTrueColorIfNot', $image);
}
public function tryConverting(&$image)
{
return $this->callPrivateFunctionByRef('tryConverting', $image);
}
/*
public function checkOperationality()
{
$this->checkOperationality();
}
public function exposedCheckConvertability()
{
$this->checkConvertability();
}
public function exposedGetImage()
{
return $this->image;
}
public function exposedCreateImageResource()
{
$this->createImageResource();
}
*/
/*
Other method for calling pnivate:
https://stackoverflow.com/questions/2738663/call-private-methods-and-private-properties-from-outside-a-class-in-php/2738847#2738847
$reflector = new \ReflectionClass(Gd::class);
$reflector->getMethod('createImageResource')->setAccessible(true);
$unlockedGate = $reflector->newInstance($source, $source . '.webp');
$unlockedGate->createImageResource();
*/
/*
$gd = new Gd($source, $source . '.webp');
$reflectedGd = new \ReflectionObject($gd);
$createImageResourceMethod = $reflectedGd->getMethod('createImageResource');
$createImageResourceMethod->setAccessible(true);
$createImageResourceMethod->invoke();
*/
// https://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/
/*
$sourceThief = function($gd) {
return $gd->source;
};
$gd = new Gd($source, $source . '.webp');
$sourceThief = \Closure::bind($sourceThief, null, $gd);
$this->assertEquals($source, $sourceThief($gd));
*/
}

View File

@@ -0,0 +1,39 @@
<?php
namespace WebPConvert\Tests\Convert\Exposers;
use WebPConvert\Convert\Converters\Vips;
/**
* Class for exposing otherwise unaccessible methods of AbstractConverter,
* - so they can be tested
*
* TODO: expose and test more methods! (and make more methods private/protected in AbstractConverter)
*/
class VipsExposer extends AbstractConverterExposer {
public function __construct($vips)
{
parent::__construct($vips);
}
public function createParamsForVipsWebPSave()
{
return $this->callPrivateFunction('createParamsForVipsWebPSave', null);
}
public function createImageResource()
{
return $this->callPrivateFunction('createImageResource', null);
}
public function doActualConvert()
{
return $this->callPrivateFunction('doActualConvert', null);
}
public function webpsave($im, $options)
{
return $this->callPrivateFunction('webpsave', null, $im, $options);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace WebPConvert\Tests\Convert\Helpers;
use WebPConvert\Convert\Helpers\JpegQualityDetector;
use PHPUnit\Framework\TestCase;
class JpegQualityDetectorTest extends TestCase
{
private static $imgDir = __DIR__ . '/../images';
public function testDetectQualityOfJpg()
{
$result = JpegQualityDetector::detectQualityOfJpg(self::$imgDir . '/small-q61.jpg');
if (is_null($result)) {
$this->addToAssertionCount(1);
} else {
$this->assertSame(61, $result);
}
}
public function testDetectQualityOfJpgNonExistantFile()
{
$result = JpegQualityDetector::detectQualityOfJpg('i dont exist');
$this->assertNull($result);
}
// TODO: Test when PNG is supplied
}

View File

@@ -0,0 +1,85 @@
<?php
namespace WebPConvert\Tests\Convert\BaseConverters;
use WebPConvert\Convert\Helpers\PhpIniSizes;
use PHPUnit\Framework\TestCase;
class PhpIniSizesTest extends TestCase
{
public function testParseShortHandSize()
{
// Test without units
$this->assertEquals(0, PhpIniSizes::parseShortHandSize('0'));
$this->assertEquals(10, PhpIniSizes::parseShortHandSize('10'));
// Test "k" unit
$this->assertEquals(1024, PhpIniSizes::parseShortHandSize('1k'));
// Test capitial "K"
$this->assertEquals(1024, PhpIniSizes::parseShortHandSize('1K'));
// Test "M" unit
$this->assertEquals(1024 * 1024, PhpIniSizes::parseShortHandSize('1M'));
// Test "G" unit
$this->assertEquals(1024 * 1024 * 1024, PhpIniSizes::parseShortHandSize('1G'));
// Moving to terrabytes, we have to be careful.
// Terrabytes cannot be represented as integers on 32 bit systems.
// (on 32 bit systems, max integer value is 107.374.182.400, which can represent up to ~107G)
// Testing floating point numbers for equality is prone to errors.
//$this->assertInternalType('int', PhpIniSizes::parseShortHandSize('10'));
//$this->assertEquals(10.0, 10);
// So, ie "200G" can not be represented by an int.
// The computation goes:
// floor($size) * pow(1024, stripos('bkmgtpezy', $unit[0]));
// floor() always returns float, according to docs (but may also
// pow() returns int unless the number is too high, in that case it returns float.
// And the result? What do you get if you multiply an int and a float (which is in fact representating an integer),
// and the result is more than PHP_INT_MAX?
// In the docs, it states the following:
// "an operation which results in a number beyond the bounds of the integer type will return a float instead."
// [https://www.php.net/manual/en/language.types.integer.php]
// Se it seems we are good.
// But let's check!
$greatComputation = floor(100) * PHP_INT_MAX;
$this->assertGreaterThan(PHP_INT_MAX, $greatComputation);
$greaterComputation = floatval(200) * floatval(PHP_INT_MAX);
$this->assertGreaterThan($greatComputation, $greaterComputation);
// Test "T" unit
$this->assertGreaterThan(PhpIniSizes::parseShortHandSize('1G'), PhpIniSizes::parseShortHandSize('100T'));
$this->assertGreaterThan(1024 * 1024 * 1024 * 1024, PhpIniSizes::parseShortHandSize('1T') + 1);
// Test that decimals are trunked, as described here:
// https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
$this->assertEquals(1024, PhpIniSizes::parseShortHandSize('1.5k'));
$this->assertEquals(0, PhpIniSizes::parseShortHandSize('0.5M'));
// Test syntax violations, which must result in parse error.
$this->assertFalse(PhpIniSizes::parseShortHandSize('0.5MM'));
$this->assertFalse(PhpIniSizes::parseShortHandSize('//5'));
}
/* TODO...
public function testTestFilesizeRequirements()
{
$iniValue = ini_get('upload_max_filesize');
// could we call ini_set? instead of mocking ini_get ?
}
*/
}

View File

@@ -0,0 +1,34 @@
<?php
namespace WebPConvert\Tests\Convert\TestConverters;
use WebPConvert\Convert\Converters\AbstractConverter;
/**
* Class for exposing otherwise unaccessible methods of AbstractConverter,
* - so they can be tested
*
* TODO: expose and test more methods! (and make more methods private/protected in AbstractConverter)
*/
class ExposedConverter extends AbstractConverter {
protected function getOptionDefinitionsExtra()
{
return [];
}
public function doActualConvert()
{
file_put_contents($this->destination, 'we-pretend-this-is-a-valid-webp!');
}
/*
public static function exposedGetMimeType($filePath)
{
$instance = self::createInstance(
$filePath,
$filePath . '.webp'
);
return $instance->getMimeTypeOfSource();
}*/
}

View File

@@ -0,0 +1,14 @@
<?php
namespace WebPConvert\Tests\Convert\TestConverters\ExtendedConverters;
use WebPConvert\Convert\Converters\Ewww;
class EwwwExtended extends Ewww
{
public function callDoActualConvert()
{
$this->doActualConvert();
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace WebPConvert\Tests\Convert\TestConverters;
use WebPConvert\Convert\Converters\AbstractConverter;
use WebPConvert\Convert\Exceptions\ConversionFailedException;
class FailureGuaranteedConverter extends AbstractConverter {
public function doActualConvert()
{
throw new ConversionFailedException('Failure guaranteed!');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace WebPConvert\Tests\Convert\TestConverters;
use WebPConvert\Convert\Converters\AbstractConverter;
class SuccessGuaranteedConverter extends AbstractConverter {
public function doActualConvert()
{
file_put_contents($this->destination, 'we-pretend-this-is-a-valid-webp!');
}
}