Просмотр исходного кода

:bath: output (+test) simplification & cleanup

codemasher 4 лет назад
Родитель
Сommit
164116fa39

+ 21 - 60
src/Output/QRImage.php → src/Output/QRGdImage.php

@@ -1,6 +1,6 @@
 <?php
 /**
- * Class QRImage
+ * Class QRGdImage
  *
  * @created      05.12.2015
  * @author       Smiley <smiley@chillerlan.net>
@@ -15,11 +15,10 @@ namespace chillerlan\QRCode\Output;
 use chillerlan\QRCode\Data\QRMatrix;
 use chillerlan\QRCode\QRCode;
 use chillerlan\Settings\SettingsContainerInterface;
-use ErrorException, Exception;
-
+use ErrorException, Throwable;
 use function array_values, count, extension_loaded, imagecolorallocate, imagecolortransparent, imagecreatetruecolor,
-	 imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, in_array,
-	is_array, ob_end_clean, ob_get_contents, ob_start, range, restore_error_handler, set_error_handler;
+	imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, is_array,
+	max, min, ob_end_clean, ob_get_contents, ob_start, restore_error_handler, set_error_handler;
 use const IMG_BICUBIC;
 
 /**
@@ -27,19 +26,7 @@ use const IMG_BICUBIC;
  *
  * @see http://php.net/manual/book.image.php
  */
-class QRImage extends QROutputAbstract{
-
-	/**
-	 * GD image types that support transparency
-	 *
-	 * @var string[]
-	 */
-	protected const TRANSPARENCY_TYPES = [
-		QRCode::OUTPUT_IMAGE_PNG,
-		QRCode::OUTPUT_IMAGE_GIF,
-	];
-
-	protected string $defaultMode = QRCode::OUTPUT_IMAGE_PNG;
+class QRGdImage extends QROutputAbstract{
 
 	/**
 	 * The GD image resource
@@ -115,7 +102,7 @@ class QRImage extends QROutputAbstract{
 		/** @phan-suppress-next-line PhanParamTooFewInternalUnpack */
 		$background = imagecolorallocate($this->image, ...$tbg);
 
-		if($this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
+		if($this->options->imageTransparent && $this->options->outputType !== QRCode::OUTPUT_IMAGE_JPG){
 			imagecolortransparent($this->image, $background);
 		}
 
@@ -188,11 +175,24 @@ class QRImage extends QROutputAbstract{
 		ob_start();
 
 		try{
-			$this->{$this->outputMode ?? $this->defaultMode}();
+
+			switch($this->options->outputType){
+				case QRCode::OUTPUT_IMAGE_GIF:
+					imagegif($this->image);
+					break;
+				case QRCode::OUTPUT_IMAGE_JPG:
+					imagejpeg($this->image, null, max(0, min(100, $this->options->jpegQuality)));
+					break;
+				// silently default to png output
+				case QRCode::OUTPUT_IMAGE_PNG:
+				default:
+					imagepng($this->image, null, max(-1, min(9, $this->options->pngCompression)));
+			}
+
 		}
 		// not going to cover edge cases
 		// @codeCoverageIgnoreStart
-		catch(Exception $e){
+		catch(Throwable $e){
 			throw new QRCodeOutputException($e->getMessage());
 		}
 		// @codeCoverageIgnoreEnd
@@ -205,43 +205,4 @@ class QRImage extends QROutputAbstract{
 		return $imageData;
 	}
 
-	/**
-	 * PNG output
-	 *
-	 * @return void
-	 */
-	protected function png():void{
-		imagepng(
-			$this->image,
-			null,
-			in_array($this->options->pngCompression, range(-1, 9), true)
-				? $this->options->pngCompression
-				: -1
-		);
-	}
-
-	/**
-	 * Jiff - like... JitHub!
-	 *
-	 * @return void
-	 */
-	protected function gif():void{
-		imagegif($this->image);
-	}
-
-	/**
-	 * JPG output
-	 *
-	 * @return void
-	 */
-	protected function jpg():void{
-		imagejpeg(
-			$this->image,
-			null,
-			in_array($this->options->jpegQuality, range(0, 100), true)
-				? $this->options->jpegQuality
-				: 85
-		);
-	}
-
 }

+ 2 - 0
src/Output/QRImagick.php

@@ -80,6 +80,8 @@ class QRImagick extends QROutputAbstract{
 			$this->options->imagickFormat
 		);
 
+		$this->imagick->setImageType(Imagick::IMGTYPE_TRUECOLOR);
+
 		$this->drawImage();
 
 		if($this->options->returnResource){

+ 27 - 4
src/Output/QRMarkup.php

@@ -43,10 +43,33 @@ class QRMarkup extends QROutputAbstract{
 		return $isDark ? $this->options->markupDark : $this->options->markupLight;
 	}
 
+	/**
+	 * @inheritDoc
+	 */
+	public function dump(string $file = null){
+		$file       ??= $this->options->cachefile;
+		$saveToFile   = $file !== null;
+
+		switch($this->options->outputType){
+			case QRCode::OUTPUT_MARKUP_HTML:
+				$data = $this->html($saveToFile);
+				break;
+			case QRCode::OUTPUT_MARKUP_SVG:
+			default:
+				$data = $this->svg($saveToFile);
+		}
+
+		if($saveToFile){
+			$this->saveToFile($data, $file);
+		}
+
+		return $data;
+	}
+
 	/**
 	 * HTML output
 	 */
-	protected function html(string $file = null):string{
+	protected function html(bool $saveToFile):string{
 
 		$html = empty($this->options->cssClass)
 			? '<div>'
@@ -66,7 +89,7 @@ class QRMarkup extends QROutputAbstract{
 
 		$html .= '</div>'.$this->options->eol;
 
-		if($file !== null){
+		if($saveToFile){
 			return sprintf(
 				'<!DOCTYPE html><head><meta charset="UTF-8"><title>QR Code</title></head><body>%s</body>',
 				$this->options->eol.$html
@@ -83,7 +106,7 @@ class QRMarkup extends QROutputAbstract{
 	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
 	 * @see https://www.sarasoueidan.com/demos/interactive-svg-coordinate-system/
 	 */
-	protected function svg(string $file = null):string{
+	protected function svg(bool $saveToFile):string{
 		$svg = $this->svgHeader();
 
 		if(!empty($this->options->svgDefs)){
@@ -96,7 +119,7 @@ class QRMarkup extends QROutputAbstract{
 		$svg .= sprintf('%1$s</svg>%1$s', $this->options->eol);
 
 		// transform to data URI only when not saving to file
-		if($file === null && $this->options->imageBase64){
+		if(!$saveToFile && $this->options->imageBase64){
 			$svg = $this->base64encode($svg, 'image/svg+xml');
 		}
 

+ 5 - 37
src/Output/QROutputAbstract.php

@@ -10,9 +10,9 @@
 
 namespace chillerlan\QRCode\Output;
 
-use chillerlan\QRCode\{Data\QRMatrix, QRCode};
+use chillerlan\QRCode\Data\QRMatrix;
 use chillerlan\Settings\SettingsContainerInterface;
-use function base64_encode, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf;
+use function base64_encode, dirname, file_put_contents, is_writable, sprintf;
 
 /**
  * common output abstract
@@ -26,18 +26,6 @@ abstract class QROutputAbstract implements QROutputInterface{
 	 */
 	protected int $moduleCount;
 
-	/**
-	 * the current output mode
-	 *
-	 * @see \chillerlan\QRCode\QROptions::$outputType
-	 */
-	protected string $outputMode;
-
-	/**
-	 * the default output mode of the current output module
-	 */
-	protected string $defaultMode;
-
 	/**
 	 * the current scaling for a QR pixel
 	 *
@@ -74,11 +62,6 @@ abstract class QROutputAbstract implements QROutputInterface{
 		$this->moduleCount = $this->matrix->size();
 		$this->scale       = $this->options->scale;
 		$this->length      = $this->moduleCount * $this->scale;
-		$class             = get_called_class();
-
-		if(isset(QRCode::OUTPUT_MODES[$class]) && in_array($this->options->outputType, QRCode::OUTPUT_MODES[$class])){
-			$this->outputMode = $this->options->outputType;
-		}
 
 		$this->setModuleValues();
 	}
@@ -136,30 +119,15 @@ abstract class QROutputAbstract implements QROutputInterface{
 	 *
 	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
 	 */
-	protected function saveToFile(string $data, string $file):bool{
+	protected function saveToFile(string $data, string $file):void{
 
 		if(!is_writable(dirname($file))){
 			throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s', $file));
 		}
 
-		return (bool)file_put_contents($file, $data);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function dump(string $file = null){
-		$file ??= $this->options->cachefile;
-
-		// call the built-in output method with the optional file path as parameter
-		// to make the called method aware if a cache file was given
-		$data = $this->{$this->outputMode ?? $this->defaultMode}($file);
-
-		if($file !== null){
-			$this->saveToFile($data, $file);
+		if(file_put_contents($file, $data) === false){
+			throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s (file_put_contents error)', $file));
 		}
-
-		return $data;
 	}
 
 }

+ 24 - 2
src/Output/QRString.php

@@ -45,10 +45,32 @@ class QRString extends QROutputAbstract{
 		return $isDark ? $this->options->textDark : $this->options->textLight;
 	}
 
+	/**
+	 * @inheritDoc
+	 */
+	public function dump(string $file = null):string{
+		$file ??= $this->options->cachefile;
+
+		switch($this->options->outputType){
+			case QRCode::OUTPUT_STRING_TEXT:
+				$data = $this->text();
+				break;
+			case QRCode::OUTPUT_STRING_JSON:
+			default:
+				$data = $this->json();
+		}
+
+		if($file !== null){
+			$this->saveToFile($data, $file);
+		}
+
+		return $data;
+	}
+
 	/**
 	 * string output
 	 */
-	protected function text(string $file = null):string{
+	protected function text():string{
 		$str = [];
 
 		foreach($this->matrix->matrix() as $row){
@@ -67,7 +89,7 @@ class QRString extends QROutputAbstract{
 	/**
 	 * JSON output
 	 */
-	protected function json(string $file = null):string{
+	protected function json():string{
 		return json_encode($this->matrix->matrix());
 	}
 

+ 16 - 30
src/QRCode.php

@@ -11,9 +11,9 @@
 namespace chillerlan\QRCode;
 
 use chillerlan\QRCode\Common\{EccLevel, ECICharset, MaskPattern, Mode};
-use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number, QRData, QRCodeDataException, QRDataModeInterface, QRMatrix};
+use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number, QRCodeDataException, QRData, QRDataModeInterface, QRMatrix};
 use chillerlan\QRCode\Decoder\{Decoder, DecoderResult, LuminanceSourceInterface};
-use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString};
+use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRGdImage, QRImagick, QRMarkup, QROutputInterface, QRString};
 use chillerlan\Settings\SettingsContainerInterface;
 use function class_exists, class_implements, in_array, mb_convert_encoding, mb_detect_encoding;
 
@@ -68,30 +68,20 @@ class QRCode{
 	public const OUTPUT_CUSTOM      = 'custom';
 
 	/**
-	 * Map of built-in output modules => capabilities
+	 * Map of built-in output modes => modules
 	 *
-	 * @var string[][]
+	 * @var string[]
 	 */
 	public const OUTPUT_MODES = [
-		QRMarkup::class => [
-			self::OUTPUT_MARKUP_SVG,
-			self::OUTPUT_MARKUP_HTML,
-		],
-		QRImage::class => [
-			self::OUTPUT_IMAGE_PNG,
-			self::OUTPUT_IMAGE_GIF,
-			self::OUTPUT_IMAGE_JPG,
-		],
-		QRString::class => [
-			self::OUTPUT_STRING_JSON,
-			self::OUTPUT_STRING_TEXT,
-		],
-		QRImagick::class => [
-			self::OUTPUT_IMAGICK,
-		],
-		QRFpdf::class => [
-			self::OUTPUT_FPDF,
-		],
+		self::OUTPUT_MARKUP_SVG  => QRMarkup::class,
+		self::OUTPUT_MARKUP_HTML => QRMarkup::class,
+		self::OUTPUT_IMAGE_PNG   => QRGdImage::class,
+		self::OUTPUT_IMAGE_GIF   => QRGdImage::class,
+		self::OUTPUT_IMAGE_JPG   => QRGdImage::class,
+		self::OUTPUT_STRING_JSON => QRString::class,
+		self::OUTPUT_STRING_TEXT => QRString::class,
+		self::OUTPUT_IMAGICK     => QRImagick::class,
+		self::OUTPUT_FPDF        => QRFpdf::class,
 	];
 
 	/**
@@ -135,9 +125,7 @@ class QRCode{
 
 					break;
 				}
-
 			}
-
 		}
 
 		return $this->initOutputInterface()->dump($file);
@@ -189,12 +177,10 @@ class QRCode{
 			return $this->initCustomOutputInterface();
 		}
 
-		foreach($this::OUTPUT_MODES as $outputInterface => $modes){
-
-			if(in_array($this->options->outputType, $modes)){
-				return new $outputInterface($this->options, $this->getMatrix());
-			}
+		$outputInterface = $this::OUTPUT_MODES[$this->options->outputType] ?? false;
 
+		if($outputInterface){
+			return new $outputInterface($this->options, $this->getMatrix());
 		}
 
 		throw new QRCodeOutputException('invalid output type');

+ 9 - 37
tests/Output/QRFpdfTest.php

@@ -11,45 +11,32 @@
 namespace chillerlan\QRCodeTest\Output;
 
 use FPDF;
-use chillerlan\QRCode\{QRCode, QROptions};
+use chillerlan\QRCode\QRCode;
 use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\Output\{QRFpdf, QROutputInterface};
+use chillerlan\QRCode\Output\QRFpdf;
 
-use function class_exists, substr;
+use function class_exists;
 
 /**
  * Tests the QRFpdf output module
  */
 final class QRFpdfTest extends QROutputTestAbstract{
 
+	protected string $FQN  = QRFpdf::class;
+	protected string $type = QRCode::OUTPUT_FPDF;
+
 	/**
 	 * @inheritDoc
 	 */
 	protected function setUp():void{
 
 		if(!class_exists(FPDF::class)){
-			$this->markTestSkipped('FPDF not available');
+			$this::markTestSkipped('FPDF not available');
 		}
 
 		parent::setUp();
 	}
 
-	/**
-	 * @inheritDoc
-	 */
-	protected function getOutputInterface(QROptions $options):QROutputInterface{
-		return new QRFpdf($options, $this->matrix);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function types():array{
-		return [
-			'fpdf' => [QRCode::OUTPUT_FPDF],
-		];
-	}
-
 	/**
 	 * @inheritDoc
 	 */
@@ -61,30 +48,15 @@ final class QRFpdfTest extends QROutputTestAbstract{
 			QRMatrix::M_DATA                     => [255, 255, 255],
 		];
 
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
 		$this->outputInterface->dump();
 
 		$this::assertTrue(true); // tricking the code coverage
 	}
 
-	/**
-	 * @inheritDoc
-	 * @dataProvider types
-	 */
-	public function testRenderImage(string $type):void{
-		$this->options->outputType  = $type;
-		$this->options->imageBase64 = false;
-
-		// substr() to avoid CreationDate
-		$expected = substr(file_get_contents(__DIR__.'/../samples/'.$type), 0, 2500);
-		$actual   = substr((new QRCode($this->options))->render('test'), 0, 2500);
-
-		$this::assertSame($expected, $actual);
-	}
-
 	public function testOutputGetResource():void{
 		$this->options->returnResource = true;
-		$this->outputInterface         = $this->getOutputInterface($this->options);
+		$this->outputInterface         = new $this->FQN($this->options, $this->matrix);
 
 		$this::assertInstanceOf(FPDF::class, $this->outputInterface->dump());
 	}

+ 22 - 0
tests/Output/QRGdImageGIFTest.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRGdImageGIFTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRGdImageGIFTest extends QRGdImageTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_IMAGE_GIF;
+
+}

+ 22 - 0
tests/Output/QRGdImageJPGTest.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRGdImageJPGTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRGdImageJPGTest extends QRGdImageTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_IMAGE_JPG;
+
+}

+ 22 - 0
tests/Output/QRGdImagePNGTest.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRGdImagePNGTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRGdImagePNGTest extends QRGdImageTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_IMAGE_PNG;
+
+}

+ 9 - 26
tests/Output/QRImageTest.php → tests/Output/QRGdImageTestAbstract.php

@@ -1,6 +1,6 @@
 <?php
 /**
- * Class QRImageTest
+ * Class QRGdImageTestAbstract
  *
  * @created      24.12.2017
  * @author       Smiley <smiley@chillerlan.net>
@@ -11,14 +11,15 @@
 namespace chillerlan\QRCodeTest\Output;
 
 use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\{QRCode, QROptions};
-use chillerlan\QRCode\Output\{QROutputInterface, QRImage};
+use chillerlan\QRCode\Output\QRGdImage;
 use const PHP_MAJOR_VERSION;
 
 /**
- * Tests the QRImage output module
+ * Tests the QRGdImage output module
  */
-final class QRImageTest extends QROutputTestAbstract{
+abstract class QRGdImageTestAbstract extends QROutputTestAbstract{
+
+	protected string $FQN  = QRGdImage::class;
 
 	/**
 	 * @inheritDoc
@@ -26,30 +27,12 @@ final class QRImageTest extends QROutputTestAbstract{
 	protected function setUp():void{
 
 		if(!extension_loaded('gd')){
-			$this->markTestSkipped('ext-gd not loaded');
+			$this::markTestSkipped('ext-gd not loaded');
 		}
 
 		parent::setUp();
 	}
 
-	/**
-	 * @inheritDoc
-	 */
-	protected function getOutputInterface(QROptions $options):QROutputInterface{
-		return new QRImage($options, $this->matrix);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function types():array{
-		return [
-			'png' => [QRCode::OUTPUT_IMAGE_PNG],
-			'gif' => [QRCode::OUTPUT_IMAGE_GIF],
-			'jpg' => [QRCode::OUTPUT_IMAGE_JPG],
-		];
-	}
-
 	/**
 	 * @inheritDoc
 	 */
@@ -61,7 +44,7 @@ final class QRImageTest extends QROutputTestAbstract{
 			QRMatrix::M_DATA                     => [255, 255, 255],
 		];
 
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
 		$this->outputInterface->dump();
 
 		$this::assertTrue(true); // tricking the code coverage
@@ -72,7 +55,7 @@ final class QRImageTest extends QROutputTestAbstract{
 	 */
 	public function testOutputGetResource():void{
 		$this->options->returnResource = true;
-		$this->outputInterface         = $this->getOutputInterface($this->options);
+		$this->outputInterface         = new $this->FQN($this->options, $this->matrix);
 
 		$actual = $this->outputInterface->dump();
 

+ 9 - 23
tests/Output/QRImagickTest.php

@@ -13,44 +13,31 @@
 
 namespace chillerlan\QRCodeTest\Output;
 
-use Imagick;
+use chillerlan\QRCode\QRCode;
 use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\{QRCode, QROptions};
-use chillerlan\QRCode\Output\{QROutputInterface, QRImagick};
+use chillerlan\QRCode\Output\QRImagick;
+use Imagick;
 
 /**
  * Tests the QRImagick output module
  */
 final class QRImagickTest extends QROutputTestAbstract{
 
+	protected string $FQN  = QRImagick::class;
+	protected string $type = QRCode::OUTPUT_IMAGICK;
+
 	/**
 	 * @inheritDoc
 	 */
 	protected function setUp():void{
 
 		if(!extension_loaded('imagick')){
-			$this->markTestSkipped('ext-imagick not loaded');
+			$this::markTestSkipped('ext-imagick not loaded');
 		}
 
 		parent::setUp();
 	}
 
-	/**
-	 * @inheritDoc
-	 */
-	protected function getOutputInterface(QROptions $options):QROutputInterface{
-		return new QRImagick($options, $this->matrix);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function types():array{
-		return [
-			'imagick' => [QRCode::OUTPUT_IMAGICK],
-		];
-	}
-
 	/**
 	 * @inheritDoc
 	 */
@@ -62,7 +49,7 @@ final class QRImagickTest extends QROutputTestAbstract{
 			QRMatrix::M_DATA                     => '#ECF9BE',
 		];
 
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
 		$this->outputInterface->dump();
 
 		$this::assertTrue(true); // tricking the code coverage
@@ -70,10 +57,9 @@ final class QRImagickTest extends QROutputTestAbstract{
 
 	public function testOutputGetResource():void{
 		$this->options->returnResource = true;
-		$this->outputInterface         = $this->getOutputInterface($this->options);
+		$this->outputInterface         = new $this->FQN($this->options, $this->matrix);
 
 		$this::assertInstanceOf(Imagick::class, $this->outputInterface->dump());
 	}
 
-
 }

+ 22 - 0
tests/Output/QRMarkupHTMLTest.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRMarkupHTMLTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRMarkupHTMLTest extends QRMarkupTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_MARKUP_HTML;
+
+}

+ 22 - 0
tests/Output/QRMarkupSVGTest.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRMarkupSVGTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRMarkupSVGTest extends QRMarkupTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_MARKUP_SVG;
+
+}

+ 5 - 21
tests/Output/QRMarkupTest.php → tests/Output/QRMarkupTestAbstract.php

@@ -1,6 +1,6 @@
 <?php
 /**
- * Class QRMarkupTest
+ * Class QRMarkupTestAbstract
  *
  * @created      24.12.2017
  * @author       Smiley <smiley@chillerlan.net>
@@ -10,31 +10,15 @@
 
 namespace chillerlan\QRCodeTest\Output;
 
-use chillerlan\QRCode\{QRCode, QROptions};
 use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\Output\{QROutputInterface, QRMarkup};
+use chillerlan\QRCode\Output\QRMarkup;
 
 /**
  * Tests the QRMarkup output module
  */
-final class QRMarkupTest extends QROutputTestAbstract{
+abstract class QRMarkupTestAbstract extends QROutputTestAbstract{
 
-	/**
-	 * @inheritDoc
-	 */
-	protected function getOutputInterface(QROptions $options):QROutputInterface{
-		return new QRMarkup($options, $this->matrix);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function types():array{
-		return [
-			'html' => [QRCode::OUTPUT_MARKUP_HTML],
-			'svg'  => [QRCode::OUTPUT_MARKUP_SVG],
-		];
-	}
+	protected string $FQN  = QRMarkup::class;
 
 	/**
 	 * @inheritDoc
@@ -48,7 +32,7 @@ final class QRMarkupTest extends QROutputTestAbstract{
 			QRMatrix::M_DATA                     => '#ECF9BE',
 		];
 
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
 		$data = $this->outputInterface->dump();
 		$this::assertStringContainsString('#4A6000', $data);
 		$this::assertStringContainsString('#ECF9BE', $data);

+ 13 - 49
tests/Output/QROutputTestAbstract.php

@@ -10,15 +10,13 @@
 
 namespace chillerlan\QRCodeTest\Output;
 
-use chillerlan\QRCode\{QRCode, QROptions};
+use chillerlan\QRCode\QROptions;
 use chillerlan\QRCode\Common\MaskPattern;
 use chillerlan\QRCode\Data\{Byte, QRData, QRMatrix};
 use chillerlan\QRCode\Output\{QRCodeOutputException, QROutputInterface};
 use PHPUnit\Framework\TestCase;
 
-use function file_exists, in_array, mkdir;
-
-use const PHP_OS_FAMILY, PHP_VERSION_ID;
+use function file_exists, mkdir;
 
 /**
  * Test abstract for the several (built-in) output modules,
@@ -31,6 +29,8 @@ abstract class QROutputTestAbstract extends TestCase{
 	protected QROutputInterface $outputInterface;
 	protected QRMatrix          $matrix;
 	protected string            $builddir = __DIR__.'/../../.build/output_test';
+	protected string            $FQN;
+	protected string            $type;
 
 	/**
 	 * Attempts to create a directory under /.build and instances several required objects
@@ -41,17 +41,14 @@ abstract class QROutputTestAbstract extends TestCase{
 			mkdir($this->builddir, 0777, true);
 		}
 
-		$this->options         = new QROptions;
-		$this->matrix          = (new QRData($this->options, [new Byte('testdata')]))
+		$this->options             = new QROptions;
+		$this->options->outputType = $this->type;
+
+		$this->matrix              = (new QRData($this->options, [new Byte('testdata')]))
 			->writeMatrix(new MaskPattern(MaskPattern::PATTERN_010));
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface     = new $this->FQN($this->options, $this->matrix);
 	}
 
-	/**
-	 * Returns a QROutputInterface instance with the given options and using $this->matrix
-	 */
-	abstract protected function getOutputInterface(QROptions $options):QROutputInterface;
-
 	/**
 	 * Validate the instance of the interface
 	 */
@@ -67,7 +64,7 @@ abstract class QROutputTestAbstract extends TestCase{
 		$this->expectExceptionMessage('Cannot write data to cache file: /foo/bar.test');
 
 		$this->options->cachefile = '/foo/bar.test';
-		$this->outputInterface = $this->getOutputInterface($this->options);
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
 		$this->outputInterface->dump();
 	}
 
@@ -80,49 +77,16 @@ abstract class QROutputTestAbstract extends TestCase{
 	 * additional, non-essential, potentially inaccurate coverage tests
 	 */
 
-	/**
-	 * @see testStringOutput()
-	 * @return string[][]
-	 */
-	abstract public function types():array;
-
 	/**
 	 * coverage of the built-in output modules
-	 *
-	 * @dataProvider types
 	 */
-	public function testStringOutput(string $type):void{
-		$this->options->outputType  = $type;
-		$this->options->cachefile   = $this->builddir.'/test.'.$type;
+	public function testRenderToCacheFile():void{
+		$this->options->cachefile   = $this->builddir.'/test.'.$this->type;
 		$this->options->imageBase64 = false;
-		$this->outputInterface      = $this->getOutputInterface($this->options);
+		$this->outputInterface      = new $this->FQN($this->options, $this->matrix);
 		$data                       = $this->outputInterface->dump(); // creates the cache file
 
 		$this::assertSame($data, file_get_contents($this->options->cachefile));
 	}
 
-	/**
-	 * covers the built-in output modules, tests against pre-rendered data
-	 *
-	 * @dataProvider types
-	 */
-	public function testRenderImage(string $type):void{
-
-		// may fail on CI, different PHP (platform) versions produce different output
-		// the samples were generated on php-7.4.3-Win32-vc15-x64
-		if(
-			(PHP_OS_FAMILY !== 'Windows' || PHP_VERSION_ID >= 80100)
-			&& in_array($type, [QRCode::OUTPUT_IMAGE_JPG, QRCode::OUTPUT_IMAGICK, QRCode::OUTPUT_MARKUP_SVG])
-		){
-			$this::markTestSkipped('may fail on CI');
-		}
-
-		$this->options->outputType = $type;
-
-		$this::assertSame(
-			trim(file_get_contents(__DIR__.'/../samples/'.$type)),
-			trim((new QRCode($this->options))->render('test'))
-		);
-	}
-
 }

+ 40 - 0
tests/Output/QRStringJSONTest.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * Class QRStringJSONTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QRCode;
+use function extension_loaded;
+
+/**
+ *
+ */
+final class QRStringJSONTest extends QRStringTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_STRING_JSON;
+
+	/**
+	 * @inheritDoc
+	 */
+	protected function setUp():void{
+		// just in case someone's running this on some weird disto that's been compiled without ext-json
+		if(!extension_loaded('json')){
+			$this::markTestSkipped('ext-json not loaded');
+		}
+
+		parent::setUp();
+	}
+
+
+	public function testSetModuleValues():void{
+		$this::markTestSkipped('N/A');
+	}
+
+}

+ 41 - 0
tests/Output/QRStringTEXTTest.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Class QRStringTEXTTest
+ *
+ * @created      11.12.2021
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2021 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+use chillerlan\QRCode\QRCode;
+
+/**
+ *
+ */
+final class QRStringTEXTTest extends QRStringTestAbstract{
+
+	protected string $type = QRCode::OUTPUT_STRING_TEXT;
+
+	/**
+	 * @inheritDoc
+	 */
+	public function testSetModuleValues():void{
+
+		$this->options->moduleValues = [
+			// data
+			QRMatrix::M_DATA | QRMatrix::IS_DARK => 'A',
+			QRMatrix::M_DATA                     => 'B',
+		];
+
+		$this->outputInterface = new $this->FQN($this->options, $this->matrix);
+		$data                  = $this->outputInterface->dump();
+
+		$this::assertStringContainsString('A', $data);
+		$this::assertStringContainsString('B', $data);
+	}
+
+}

+ 0 - 74
tests/Output/QRStringTest.php

@@ -1,74 +0,0 @@
-<?php
-/**
- * Class QRStringTest
- *
- * @created      24.12.2017
- * @author       Smiley <smiley@chillerlan.net>
- * @copyright    2017 Smiley
- * @license      MIT
- */
-
-namespace chillerlan\QRCodeTest\Output;
-
-use chillerlan\QRCode\{QRCode, QROptions};
-use chillerlan\QRCode\Common\EccLevel;
-use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\Output\{QROutputInterface, QRString};
-use chillerlan\QRCodeExamples\MyCustomOutput;
-
-/**
- * Tests the QRString output module
- */
-final class QRStringTest extends QROutputTestAbstract{
-
-	/**
-	 * @inheritDoc
-	 */
-	protected function getOutputInterface(QROptions $options):QROutputInterface{
-		return new QRString($options, $this->matrix);
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function types():array{
-		return [
-			'json' => [QRCode::OUTPUT_STRING_JSON],
-			'text' => [QRCode::OUTPUT_STRING_TEXT],
-		];
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	public function testSetModuleValues():void{
-
-		$this->options->moduleValues = [
-			// data
-			QRMatrix::M_DATA | QRMatrix::IS_DARK => 'A',
-			QRMatrix::M_DATA                     => 'B',
-		];
-
-		$this->outputInterface = $this->getOutputInterface($this->options);
-		$data                  = $this->outputInterface->dump();
-
-		$this::assertStringContainsString('A', $data);
-		$this::assertStringContainsString('B', $data);
-	}
-
-	/**
-	 * covers the custom output functionality via an example
-	 */
-	public function testCustomOutput():void{
-		$this->options->version         = 5;
-		$this->options->eccLevel        = EccLevel::L;
-		$this->options->outputType      = QRCode::OUTPUT_CUSTOM;
-		$this->options->outputInterface = MyCustomOutput::class;
-
-		$this::assertSame(
-			file_get_contents(__DIR__.'/../samples/custom'),
-			(new QRCode($this->options))->render('test')
-		);
-	}
-
-}

+ 22 - 0
tests/Output/QRStringTestAbstract.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Class QRStringTestAbstract
+ *
+ * @created      24.12.2017
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2017 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Output\QRString;
+
+/**
+ * Tests the QRString output module
+ */
+abstract class QRStringTestAbstract extends QROutputTestAbstract{
+
+	protected string $FQN  = QRString::class;
+
+}

+ 0 - 45
tests/samples/custom

@@ -1,45 +0,0 @@
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000
-000011111110111010000101111010000011111110000
-000010000010111000001101011000001010000010000
-000010111010101101011000001101011010111010000
-000010111010110100111110010100111010111010000
-000010111010000001101011000001101010111010000
-000010000010100111110010100111110010000010000
-000011111110101010101010101010101011111110000
-000000000000010010100111110010100000000000000
-000011001110000101111010000101111001011110000
-000000000000111010000101111010000111100010000
-000001011010100111110010100111110011001010000
-000010000101111101011000001101011110011110000
-000000011010100011000001101011000101110100000
-000011001100001001101011000001101010011010000
-000010110111110000001101011000001100110100000
-000010000100100010100111110010100001100100000
-000011111110111101111010000101111010100110000
-000011010000111010000101111010000111100100000
-000010101111111111110010100111110011001000000
-000010110001110101011000001101011110011010000
-000001001111100011000001101011000101110010000
-000011000100110001101011000001101010011100000
-000001000011001000001101011000001100110000000
-000011101001011010100111110010100001100000000
-000010111010001101111010000101111010100110000
-000011100000001010000101111010000111100000000
-000000001110110111110010100111110011001000000
-000000011001011101011000001101011110011100000
-000011111110101011000001101011001111110110000
-000000000000110001101011000001101000111100000
-000011111110001000001101011000011010110000000
-000010000010101010100111110010101000100100000
-000010111010111101111010000101111111100110000
-000010111010011010000101111010001101100010000
-000010111010000111110010100111100101101100000
-000010000010101101011000001101001100111100000
-000011111110101011000001101011000110010110000
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000

BIN
tests/samples/fpdf


+ 0 - 1
tests/samples/gif

@@ -1 +0,0 @@
-data:image/gif;base64,R0lGODlhkQCRAIAAAAQCBP///yH5BAEAAAEALAAAAACRAJEAAAL+jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpfMpvOpBEin1Kr1ek1gpY6qdgsOU1niMviL7Y4R5raV7I4D0NmGly13w/Nm+tu+dsDXtjcY5nfHkGhgWFY4x7GoIOlXGRmYQnmhKYg56clZEToyOjF6CuqJURrCGoE6pRaLN7vh+nH7AMsFWMuouglcIklIy9vpG0CcmlyMfJzJLGb5DFlN/dvcZ2wdre3Ija0s3T3+PR2+sgx+nd7+ng1tjg6Psk4fX36vT464JX5i3xl3+WTJE+esoDpyA+vtKodwW72ADP8RnAfxYkT+dgpVCLToUFjHBR/TaDRRsk7IZAAvJsT4yJ/Jlfh0VZw50t5NlTlfGuTHEebCc4dcSoSQ8s9ElDuV9jxqk2jDnBSlgnwa9KdMnkI9iqSQa9VXU2NblX11VkPYXgeZsgz2FsRaRWk9zCVZV2xcUXkv7QXb18LdT39FNKq5b+NhnDoXM05s1DHXqpIh0wRaObDazJaxyuM8WC9ozKQVg4bC1ilqHVNX52jt+gbs2DVm087nM/Lnrw9bh4YbR6vujEur+dacgY/wy8vxBv0tOE/zrlRPGr9KvXHw1Kanb1UNne/flw9bXu6snThu7OWtewaPXLR6jMfH9+PODT3l+eT+ed+naxVRMaVWX1vM4XedgEPtFuBkCK4nx0/hAaZggg4CyKAhEsYHXGn5YTfdYhsWZlaFEF7oXIaDjGggCejlhiFpyhHIYXQNzvedabnot6CMdRXoI4kHvpAUWY81ZaSKMRQpAZA5NvmfC0yideSNSXpIg5Pu0ceef1W22IKWxZ0In31f4tjji14itmaZYD6ipplsyukmml6daR6ZPFqI5W17vtfdbYA+mN2fUBgap5KCFtpmoGMeGiVhig4p5WhvbgmkbZVaeiWLQaIYpqV2VsfndxN2IOqo2T3J56l+jdYpjTe6akuNpL4HI5k2TNheqyB+KKQ3l1IJZlKachn+bHqoNgpsTazOwCuzvjL2rAzGRmqqtEhBtV+2JkpaVIxXHmtYU4hyu6W3w+JiLrbNqpYnuOSWqKKYKYZ777i/DtPut/M+am+os0b6763ITrppvV1aCSWdhnb7bqLwElotreIpjOe7scb4sFsYcyXxud8u2S/CjGYsbro9qtvnySBruyoM1/qLJKbuEllyy1Ma3PGd60b1sR7D9SqsqiEepiPMENc68HM1p+yz0YSKOLTSHksNtZ5Q7QwunJlVvK/BO6QKNrUqvyZq2aBanB5nak/86Nhpa0x31ovejXfeeu/Nd99+/w144IIPTnjhhh+OeOKKL854444/DnnkkhcCXgAAOw==

+ 0 - 31
tests/samples/html

@@ -1,31 +0,0 @@
-<div class="qrcode">
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #000;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-<div><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span><span style="background: #fff;"></span></div>
-</div>

BIN
tests/samples/imagick


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tests/samples/jpg


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tests/samples/json


+ 0 - 1
tests/samples/png

@@ -1 +0,0 @@
-data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJEAAACRCAIAAABMus10AAAABnRSTlMA/wD/AP83WBt9AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACd0lEQVR4nO3dQW7jIABA0fFo7n/ldFnJC0sMBvu3762bJtUXMnUwHJ/P5w8pf5/+AAzTrEezHs16NOvRrEezHs16NOvRrEezHs16NOvRrEezHs16NOvRrEeznn8zLz6O467Pce20aOX6fa9XuJxeO/SbbzSzDMc469GsR7MezXqm5iAnNy5vHZplrJs4bPuLhhhnPZr1aNajWc+dc5CToavu0NV+6F7GU/OIdQ8cGWc9mvVo1qNZz8I5yFO2TUmeYpz1aNajWY9mPT9hDjKzPKTIOOvRrEezHs16Fs5B1l38n5pWvGQ6Y5z1aNajWY9mPXfOQbY9VDKzHmToq5ltf9EQ46xHsx7NejTrOV7yv/0M38Xwdpr1aNajWc9j+4PcuIvHzKO6626LrFsaa5z1aNajWY9mPfv2BzldhGd2AJm5gM9MOp7a0OzEOOvRrEezHs169u0PMnQB3/ZA7Utumgwxzno069GsR7Oefc/mzkwrtq34uHGrtJnffM0469GsR7MezXqm5iAzx7hse3pl3eKRpxhnPZr1aNajWc9j58XM3DXYtle79SDcQ7MezXo060mem7ttecg717AYZz2a9WjWo1lP8tzc6x9ed7fCfRD+k2Y9mvVo1pM8N3fmfbftALJuHa1x1qNZj2Y9mvUkz6y78fJ+4+LXbef1Gmc9mvVo1qNZT3IOcjLzeM6697UehG+a9WjWo1lP8tzck3WLR2Yez5n54WvGWY9mPZr1aNaTPDf32szK0XW3NnwX86tp1qNZj2Y9P+Hc3N/GOOvRrEezHs16NOvRrEezHs16NOvRrEezHs16NOvRrEezHs16NOvRrEezni+wifc/oOyB/wAAAABJRU5ErkJggg==

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tests/samples/svg


+ 0 - 29
tests/samples/text

@@ -1,29 +0,0 @@
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴🔴🔴🔴🔴🔴🔴⭕🔴🔴⭕⭕🔴⭕🔴🔴🔴🔴🔴🔴🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕🔴⭕⭕🔴⭕⭕🔴⭕🔴⭕⭕⭕⭕⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕🔴⭕🔴⭕🔴⭕🔴⭕🔴🔴🔴⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕🔴⭕⭕🔴⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕🔴🔴🔴⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴🔴🔴🔴🔴🔴🔴⭕🔴⭕🔴⭕🔴⭕🔴🔴🔴🔴🔴🔴🔴⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕🔴🔴⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴🔴🔴🔴⭕⭕🔴⭕🔴⭕🔴⭕⭕🔴⭕⭕🔴🔴🔴⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕⭕🔴🔴🔴⭕🔴⭕⭕🔴⭕🔴⭕⭕🔴⭕🔴🔴⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴⭕🔴🔴🔴⭕⭕⭕🔴⭕🔴🔴🔴🔴🔴⭕⭕🔴🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴⭕⭕⭕🔴🔴⭕🔴⭕🔴🔴⭕⭕⭕🔴⭕🔴⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕🔴🔴⭕🔴⭕🔴⭕⭕🔴🔴🔴⭕🔴⭕⭕🔴🔴⭕🔴⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕🔴⭕🔴⭕⭕🔴⭕🔴⭕🔴⭕🔴⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴🔴🔴🔴🔴🔴🔴⭕⭕⭕🔴⭕⭕🔴🔴⭕🔴🔴🔴⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕🔴⭕⭕🔴⭕🔴🔴🔴🔴⭕⭕🔴🔴⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕⭕🔴🔴🔴⭕⭕🔴⭕⭕⭕🔴🔴🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕🔴🔴⭕⭕⭕🔴⭕⭕🔴🔴⭕🔴⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕🔴🔴🔴⭕🔴⭕🔴⭕🔴🔴⭕🔴⭕⭕🔴⭕🔴⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕🔴⭕⭕⭕⭕⭕🔴⭕🔴🔴🔴🔴🔴⭕🔴⭕🔴🔴⭕⭕🔴⭕⭕⭕⭕
-⭕⭕⭕⭕🔴🔴🔴🔴🔴🔴🔴⭕🔴🔴⭕🔴🔴⭕⭕🔴⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕
-⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕

Некоторые файлы не были показаны из-за большого количества измененных файлов