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

:sparkles: more tests & cleanup

smiley 8 лет назад
Родитель
Сommit
019d932d35

+ 103 - 32
src/Output/QRImage.php

@@ -12,14 +12,18 @@
 
 namespace chillerlan\QRCode\Output;
 
-use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\QRCode;
+use chillerlan\QRCode\{QRCode, Data\QRMatrix};
 
 /**
  * Converts the matrix into images, raw or base64 output
  */
 class QRImage extends QROutputAbstract{
 
+	const transparencyTypes = [
+		QRCode::OUTPUT_IMAGE_PNG,
+		QRCode::OUTPUT_IMAGE_GIF,
+	];
+
 	protected $moduleValues = [
 		// light
 		QRMatrix::M_DATA            => [255, 255, 255],
@@ -42,77 +46,144 @@ class QRImage extends QROutputAbstract{
 		QRMatrix::M_TEST << 8       => [0, 0, 0],
 	];
 
+	/**
+	 * @see imagecreatetruecolor()
+	 * @var resource
+	 */
+	protected $image;
+
+	/**
+	 * @var int
+	 */
+	protected $scale;
+
+	/**
+	 * @var int
+	 */
+	protected $length;
+
+	/**
+	 * @see imagecolorallocate()
+	 * @var int
+	 */
+	protected $background;
+
 	/**
 	 * @return string
+	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
 	 */
 	public function dump():string{
-		$scale        = $this->options->scale;
-		$length       = $this->moduleCount * $scale;
-		$image        = imagecreatetruecolor($length, $length);
-		$background   = imagecolorallocate($image, ...$this->options->imageTransparencyBG);
-		$moduleValues = is_array($this->options->moduleValues[QRMatrix::M_DATA])
-			? $this->options->moduleValues // @codeCoverageIgnore
-			: $this->moduleValues;
 
-		if((bool)$this->options->imageTransparent && in_array($this->options->outputType, [QRCode::OUTPUT_IMAGE_PNG, QRCode::OUTPUT_IMAGE_GIF,], true)){
-			imagecolortransparent($image, $background);
+		if($this->options->cachefile !== null && !is_writable(dirname($this->options->cachefile))){
+			throw new QRCodeOutputException('Could not write data to cache file: '.$this->options->cachefile);
 		}
 
-		imagefilledrectangle($image, 0, 0, $length, $length, $background);
+		$this->setImage();
+
+		$moduleValues = is_array($this->options->moduleValues[$this->matrix::M_DATA])
+			? $this->options->moduleValues // @codeCoverageIgnore
+			: $this->moduleValues;
 
 		foreach($this->matrix->matrix() as $y => $row){
 			foreach($row as $x => $pixel){
-				$color = imagecolorallocate($image, ...$moduleValues[$pixel]);
-
-				imagefilledrectangle($image, $x * $scale, $y * $scale, ($x + 1) * $scale - 1, ($y + 1) * $scale - 1, $color);
+				$this->setPixel($x, $y, imagecolorallocate($this->image, ...$moduleValues[$pixel]));
 			}
 		}
 
+		$imageData = $this->dumpImage();
+
+		if((bool)$this->options->imageBase64){
+			$imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
+		}
+
+		return $imageData;
+	}
+
+	/**
+	 * @return void
+	 */
+	protected function setImage(){
+		$this->scale        = $this->options->scale;
+		$this->length       = $this->moduleCount * $this->scale;
+		$this->image        = imagecreatetruecolor($this->length, $this->length);
+		$this->background   = imagecolorallocate($this->image, ...$this->options->imageTransparencyBG);
+
+		if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::transparencyTypes, true)){
+			imagecolortransparent($this->image, $this->background);
+		}
+
+		imagefilledrectangle($this->image, 0, 0, $this->length, $this->length, $this->background);
+	}
+
+	/**
+	 * @param $x
+	 * @param $y
+	 * @param $color
+	 * @return void
+	 */
+	protected function setPixel($x, $y, $color){
+		imagefilledrectangle(
+			$this->image,
+			$x * $this->scale,
+			$y * $this->scale,
+			($x + 1) * $this->scale - 1,
+			($y + 1) * $this->scale - 1,
+			$color
+		);
+	}
+
+	/**
+	 * @return string
+	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+	 */
+	protected function dumpImage():string {
 		ob_start();
 
-		call_user_func_array([$this, $this->options->outputType ?? QRCode::OUTPUT_IMAGE_PNG], [&$image]);
+		try{
+			call_user_func([$this, $this->options->outputType ?? QRCode::OUTPUT_IMAGE_PNG]);
+		}
+		// not going to cover edge cases
+		// @codeCoverageIgnoreStart
+		catch(\Exception $e){
+			throw new QRCodeOutputException($e->getMessage());
+		}
+		// @codeCoverageIgnoreEnd
 
 		$imageData = ob_get_contents();
-		imagedestroy($image);
+		imagedestroy($this->image);
 
 		ob_end_clean();
 
-		if((bool)$this->options->imageBase64){
-			$imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
-		}
-
 		return $imageData;
 	}
 
 	/**
-	 * @param $image
+	 * @return void
 	 */
-	protected function png(&$image){
+	protected function png(){
 		imagepng(
-			$image,
+			$this->image,
 			$this->options->cachefile,
 			in_array($this->options->pngCompression, range(-1, 9), true)
 				? $this->options->pngCompression
 				: -1
 		);
-
 	}
 
 	/**
 	 * Jiff - like... JitHub!
-	 *
-	 * @param $image
+	 * @return void
 	 */
-	protected function gif(&$image){
-		imagegif($image, $this->options->cachefile);
+	protected function gif(){
+		imagegif($this->image, $this->options->cachefile);
 	}
 
 	/**
-	 * @param $image
+	 * @return void
 	 */
-	protected function jpg(&$image){
+	protected function jpg(){
 		imagejpeg(
-			$image,
+			$this->image,
 			$this->options->cachefile,
 			in_array($this->options->jpegQuality, range(0, 100), true)
 				? $this->options->jpegQuality

+ 16 - 14
src/Output/QRMarkup.php

@@ -23,13 +23,20 @@ class QRMarkup extends QROutputAbstract{
 	 * @return string
 	 */
 	public function dump(){
-		switch($this->options->outputType){
-			case QRCode::OUTPUT_MARKUP_HTML:
-				return $this->toHTML();
-			case QRCode::OUTPUT_MARKUP_SVG :
-			default:
-				return $this->toSVG();
+
+		if($this->options->cachefile !== null && !is_writable(dirname($this->options->cachefile))){
+			throw new QRCodeOutputException('Could not write data to cache file: '.$this->options->cachefile);
+		}
+
+		$data = $this->options->outputType === QRCode::OUTPUT_MARKUP_HTML
+			? $this->toHTML()
+			: $this->toSVG();
+
+		if($this->options->cachefile !== null){
+			$this->saveToFile($data);
 		}
+
+		return $data;
 	}
 
 	/**
@@ -45,14 +52,11 @@ class QRMarkup extends QROutputAbstract{
 				$html .= '<span style="background: '.($this->options->moduleValues[$pixel] ?: 'lightgrey').';"></span>';
 			}
 
-			$html .= '</div>';
-			$html .= $this->options->eol;
+			$html .= '</div>'.$this->options->eol;
 		}
 
 		if($this->options->cachefile){
-			$html = '<!DOCTYPE html><head><meta charset="UTF-8"></head><body>'.$this->options->eol.$html.'</body>';
-
-			return $this->saveToFile($html);
+			return '<!DOCTYPE html><head><meta charset="UTF-8"></head><body>'.$this->options->eol.$html.'</body>';
 		}
 
 		return $html;
@@ -117,9 +121,7 @@ class QRMarkup extends QROutputAbstract{
 
 		// if saving to file, append the correct headers
 		if($this->options->cachefile){
-			$svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.$this->options->eol.$svg;
-
-			return $this->saveToFile($svg);
+			return '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.$this->options->eol.$svg;
 		}
 
 		return $svg;

+ 10 - 26
src/Output/QROutputAbstract.php

@@ -12,9 +12,7 @@
 
 namespace chillerlan\QRCode\Output;
 
-use chillerlan\QRCode\{
-	Data\QRMatrix, QROptions
-};
+use chillerlan\QRCode\{Data\QRMatrix, QROptions};
 
 /**
  *
@@ -41,36 +39,22 @@ abstract class QROutputAbstract implements QROutputInterface{
 	 *
 	 * @param \chillerlan\QRCode\QROptions     $options
 	 * @param \chillerlan\QRCode\Data\QRMatrix $matrix
-	 *
-	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
 	 */
 	public function __construct(QROptions $options, QRMatrix $matrix){
-		$this->options = $options;
-
-		$this->moduleCount = $matrix->size();
-
-		if($this->moduleCount < 21){  // minimum QR modules @todo: quet zone
-			throw new QRCodeOutputException('Invalid matrix!');
-		}
-
-		$this->matrix = $matrix;
+		$this->options     = $options;
+		$this->matrix      = $matrix;
+		$this->moduleCount = $this->matrix->size();
 	}
 
 	/**
-	 * @param string $data
+	 * @see file_put_contents()
 	 *
-	 * @return bool
-	 * @throws \chillerlan\QRCode\Output\QRCodeOutputException
-	 */
-	protected function saveToFile(string $data):bool {
-
-		try{
-			return (bool)file_put_contents($this->options->cachefile, $data);
-		}
-		catch(\Exception $e){
-			throw new QRCodeOutputException('Could not write data to cache file: '.$e->getMessage());
-		}
+	 * @param string $data
 
+	 * @return bool|int
+	 */
+	protected function saveToFile(string $data) {
+		return file_put_contents($this->options->cachefile, $data);
 	}
 
 }

+ 22 - 13
src/Output/QRString.php

@@ -24,39 +24,48 @@ class QRString extends QROutputAbstract{
 	 */
 	public function dump():string{
 
-		switch($this->options->outputType){
-			case QRCode::OUTPUT_STRING_TEXT:
-				return $this->toString();
-			case QRCode::OUTPUT_STRING_JSON:
-			default:
-				return json_encode($this->matrix->matrix());
+		$data = $this->options->outputType === QRCode::OUTPUT_STRING_JSON
+			? json_encode($this->matrix->matrix())
+			: $this->toString();
+
+		if($this->options->cachefile !== null){
+
+			if(!is_writable(dirname($this->options->cachefile))){
+				throw new QRCodeOutputException('Could not write data to cache file: '.$this->options->cachefile);
+			}
+
+			$this->saveToFile($data);
 		}
 
+		return $data;
 	}
 
 	/**
 	 * @return string
 	 */
 	protected function toString():string{
-		$str = '';
+		$str = [];
 
 		foreach($this->matrix->matrix() as $row){
+			$r = [];
+
 			foreach($row as $col){
 				$col = $this->options->moduleValues[$col];
-				
+
 				// fallback
 				if(is_bool($col) || !is_string($col)){
-					$col = $col ? $this->options->textDark : $this->options->textLight;
+					$col = $col
+						? $this->options->textDark
+						: $this->options->textLight;
 				}
 
-
-				$str .= $col;
+				$r[] = $col;
 			}
 
-			$str .= $this->options->eol;
+			$str[] = implode('', $r);
 		}
 
-		return $str;
+		return implode($this->options->eol, $str);
 	}
 
 }

+ 0 - 2
src/QRCode.php

@@ -321,8 +321,6 @@ class QRCode{
 	/**
 	 * a dummy
 	 *
-	 * @codeCoverageIgnore
-	 *
 	 * @param $data
 	 *
 	 * @return bool

+ 52 - 0
tests/Output/QRImageTest.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * Class QRImageTest
+ *
+ * @filesource   QRImageTest.php
+ * @created      24.12.2017
+ * @package      chillerlan\QRCodeTest\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2017 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Output\QRImage;
+use chillerlan\QRCode\QRCode;
+
+class QRImageTest extends QROutputTestAbstract{
+
+	protected $FQCN = QRImage::class;
+
+	public function types(){
+		return [
+			[QRCode::OUTPUT_IMAGE_PNG],
+			[QRCode::OUTPUT_IMAGE_GIF],
+			[QRCode::OUTPUT_IMAGE_JPG],
+		];
+	}
+
+	/**
+	 * @dataProvider types
+	 * @param $type
+	 */
+	public function testImageOutput($type){
+		$this->options->outputType = $type;
+		$this->options->cachefile  = $this::cachefile.$type;
+		$this->setOutputInterface();
+		$this->outputInterface->dump();
+
+		$this->options->cachefile = null;
+		$this->options->imageBase64 = false;
+		$this->setOutputInterface();
+		$img = $this->outputInterface->dump();
+
+		if($type === QRCode::OUTPUT_IMAGE_JPG){ // jpeg encoding may cause different results
+			$this->markAsRisky();
+		}
+
+		$this->assertSame($img, file_get_contents($this::cachefile.$type));
+	}
+
+}

+ 64 - 0
tests/Output/QRMarkupTest.php

@@ -0,0 +1,64 @@
+<?php
+/**
+ * Class QRMarkupTest
+ *
+ * @filesource   QRMarkupTest.php
+ * @created      24.12.2017
+ * @package      chillerlan\QRCodeTest\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2017 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Output\QRMarkup;
+use chillerlan\QRCode\QRCode;
+
+class QRMarkupTest extends QROutputTestAbstract{
+
+	protected $FQCN = QRMarkup::class;
+
+	public function types(){
+		return [
+			[QRCode::OUTPUT_MARKUP_HTML],
+			[QRCode::OUTPUT_MARKUP_SVG],
+		];
+	}
+
+	/**
+	 * @dataProvider types
+	 * @param $type
+	 */
+	public function testMarkupOutputFile($type){
+		$this->options->outputType = $type;
+		$this->options->cachefile  = $this::cachefile.$type;
+		$this->setOutputInterface();
+		$data = $this->outputInterface->dump();
+
+		$this->assertSame($data, file_get_contents($this->options->cachefile));
+	}
+
+	/**
+	 * @dataProvider types
+	 * @param $type
+	 */
+	public function testMarkupOutput($type){
+		$this->options->outputType = $type;
+		$this->setOutputInterface();
+
+		$expected = explode($this->options->eol, file_get_contents($this::cachefile.$type));
+		// cut off the doctype & head
+		array_shift($expected);
+
+		if($type === QRCode::OUTPUT_MARKUP_HTML){
+			// cut off the </body> tag
+			array_pop($expected);
+		}
+
+		$expected = implode($this->options->eol, $expected);
+
+		$this->assertSame(trim($expected), trim($this->outputInterface->dump()));
+	}
+
+}

+ 67 - 0
tests/Output/QROutputTestAbstract.php

@@ -0,0 +1,67 @@
+<?php
+/**
+ * Class QROutputTestAbstract
+ *
+ * @filesource   QROutputTestAbstract.php
+ * @created      24.12.2017
+ * @package      chillerlan\QRCodeTest\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2017 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Data\Byte;
+use chillerlan\QRCode\Output\QROutputInterface;
+use chillerlan\QRCode\QROptions;
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+/**
+ */
+abstract class QROutputTestAbstract extends QRTestAbstract{
+
+	const cachefile = __DIR__.'/output_test.';
+
+	/**
+	 * @var \chillerlan\QRCode\Output\QROutputInterface
+	 */
+	protected $outputInterface;
+
+	/**
+	 * @var \chillerlan\QRCode\QROptions
+	 */
+	protected $options;
+
+	/**
+	 * @var \chillerlan\QRCode\Data\QRMatrix
+	 */
+	protected $matrix;
+
+	protected function setUp(){
+		parent::setUp();
+
+		$this->options         = new QROptions;
+		$this->setOutputInterface();
+	}
+
+	protected function setOutputInterface(){
+		$this->outputInterface = $this->reflection->newInstanceArgs([$this->options, (new Byte($this->options, 'testdata'))->initMatrix(0)]);
+		return $this->outputInterface;
+	}
+
+	public function testInstance(){
+		$this->assertInstanceOf(QROutputInterface::class, $this->outputInterface);
+	}
+
+	/**
+	 * @expectedException \chillerlan\QRCode\Output\QRCodeOutputException
+	 * @expectedExceptionMessage Could not write data to cache file: /foo
+	 */
+	public function testSaveException(){
+		$this->options->cachefile = '/foo';
+		$this->setOutputInterface();
+		$this->outputInterface->dump();
+	}
+
+}

+ 42 - 0
tests/Output/QRStringTest.php

@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class QRStringTest
+ *
+ * @filesource   QRStringTest.php
+ * @created      24.12.2017
+ * @package      chillerlan\QRCodeTest\Output
+ * @author       Smiley <smiley@chillerlan.net>
+ * @copyright    2017 Smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\Output\QRString;
+use chillerlan\QRCode\QRCode;
+
+class QRStringTest extends QROutputTestAbstract{
+
+	protected $FQCN = QRString::class;
+
+	public function types(){
+		return [
+			[QRCode::OUTPUT_STRING_JSON],
+			[QRCode::OUTPUT_STRING_TEXT],
+		];
+	}
+
+	/**
+	 * @dataProvider types
+	 * @param $type
+	 */
+	public function testStringOutput($type){
+		$this->options->outputType = $type;
+		$this->options->cachefile  = $this::cachefile.$type;
+		$this->setOutputInterface();
+		$data = $this->outputInterface->dump();
+
+		$this->assertSame($data, file_get_contents($this->options->cachefile));
+	}
+
+}

+ 7 - 17
tests/QRCodeTest.php

@@ -30,21 +30,6 @@ class QRCodeTest extends QRTestAbstract{
 		$this->qrcode = $this->reflection->newInstance();
 	}
 
-	/*
-	public function optionsDataProvider(){
-		return [
-			[QROptions::class],
-#			[],
-		];
-	}
-
-	public function testInstance($options){
-		$q = $this->reflection->newInstanceArgs([new $options]);
-		$this->assertInstanceOf($this->FQCN, $q);
-#		print_r($q->render('test'));
-	}
-	*/
-
 	public function testIsNumber(){
 		$this->assertTrue($this->qrcode->isNumber('0123456789'));
 		$this->assertFalse($this->qrcode->isNumber('ABC'));
@@ -100,7 +85,12 @@ class QRCodeTest extends QRTestAbstract{
 		$this->qrcode->setOptions(new QROptions(['outputType' => 'foo']))->render('test');
 	}
 
-
-
+	/**
+	 * @expectedException \chillerlan\QRCode\Data\QRCodeDataException
+	 * @expectedExceptionMessage QRCode::getMatrix() No data given.
+	 */
+	public function testGetMatrixException(){
+		$this->qrcode->getMatrix('');
+	}
 
 }

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


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