| 
<?php/**
 * StegoSystem Base LSB UnitTest
 *
 * @link        https://github.com/picamator/SteganographyKit
 * @license     http://opensource.org/licenses/BSD-3-Clause New BSD License
 */
 
 use Picamator\SteganographyKit\SecretText\PlainText;
 use Picamator\SteganographyKit\Image\Image;
 use Picamator\SteganographyKit\StegoSystem\StegoSystemInterface;
 
 abstract class BaseLsbTest extends BaseTest
 {
 /**
 * SecretText file
 *
 * @var string
 */
 protected $secretFile = 'secret_text.txt';
 
 /**
 * CoverText options
 *
 * @var array
 */
 static protected $optionsCoverText = array(
 'path'      => 'original_200_200.png',
 'savePath'  => 'original_%s.png'
 );
 
 /**
 * Remove files in stegoPath after runs each test
 */
 public function tearDown()
 {
 $this->clearStegoPath();
 }
 
 /**
 * Base Encode Decode
 *
 * @param array                 $optionsCoverText
 * @param array                 $optionsSecretText
 * @param array                 $channels
 * @param StegoSystemInterface  $stegoSystem
 */
 protected function encodeDecode(array $optionsCoverText,
 array $optionsSecretText, array $channels, StegoSystemInterface $stegoSystem
 ) {
 // encode
 $optionsCoverText['path']       = $this->getDataPath($optionsCoverText['path']);
 $optionsCoverText['savePath']   = dirname($optionsCoverText['path']) . '/'
 . $optionsCoverText['savePath'];
 
 $coverText      = new Image($optionsCoverText);
 $secretText     = new PlainText($optionsSecretText);
 
 $encode = $stegoSystem->setChannels($channels)->encode($secretText, $coverText);
 
 $this->assertTrue($encode);
 
 // decode
 $stegoText  = new Image(array('path' => $optionsCoverText['savePath']));
 $decodeText = $stegoSystem->decode($stegoText, $secretText);
 
 $this->assertEquals($optionsSecretText['text'], $decodeText);
 }
 
 /**
 * Generate data provider
 * It's use secret_text.txt as a secret text and
 * original_200_200.png as a cover tet
 *
 * @param integer $resultCount  - number of providers data
 * @param integer $textLength   - text length, if not set random data is used
 * @param integer $channel      - channel, if not set random data is used
 */
 protected function generateProvider($resultCount,
 $textLength = null, array $channel = []
 ) {
 $supportedChannel       = array('red', 'green', 'blue');
 $supportedChannelSize   = count($supportedChannel);
 
 // 200*200*3/8 = 15000 characters max to cover
 // 19433 secret text length
 $secretText         = $this->getSecretFileData();
 $secretTextLength   = strlen($secretText);
 
 // validate parameters
 self::validatePrameters($textLength, $secretTextLength, $channel, $supportedChannelSize);
 
 // generate provider data set
 $providerData = [];
 for($i = 0; $i < $resultCount; $i++) {
 // generate secretText item
 $secretTextItem = (is_null($textLength))?
 self::getRandomText($secretText, $secretTextLength):
 substr($secretText, 0, $textLength);
 
 // generate use channel
 $useChannel = (empty($channel))?
 self::getRandomChannel($supportedChannel, $supportedChannelSize):
 $channel;
 
 // set coverText options
 $providerData[$i][] = self::getProviderDataItem($useChannel, $secretTextItem);
 
 // set secretText option
 $providerData[$i][] = array('text' => $secretTextItem);
 
 // set use channel
 $providerData[$i][] = $useChannel;
 }
 
 return $providerData;
 }
 
 /**
 * Gets secret data from file
 *
 * @return string|false
 * @throws \PHPUnit_Framework_Exception
 */
 protected function getSecretFileData()
 {
 $result = file_get_contents($this->getDataPath($this->secretFile));
 if ($result === false) {
 throw new \PHPUnit_Framework_Exception('Can not read secretFile: ' . $this->secretFile);
 }
 
 return $result;
 }
 
 /**
 * Validate provider paramters
 *
 * @param integer $textLength
 * @param integer $secretTextLength
 * @param array $channel
 * @param integer $supportedChannelSize
 * @throws \PHPUnit_Framework_Exception
 */
 static protected function validatePrameters($textLength,
 $secretTextLength, array $channel, $supportedChannelSize
 ) {
 if ((!is_null($textLength) &&  $textLength > $secretTextLength)
 || (!empty($channel) && count($channel) > $supportedChannelSize)) {
 
 throw new \PHPUnit_Framework_Exception('Used parameters are out of data source length: text ['
 . $secretTextLength . '], channels [' . $supportedChannelSize . ']');
 }
 }
 
 /**
 * Gets provider's data item
 *
 * @param array $useChannel
 * @param string $secretTextItem
 * @return array - array('path' => ..., 'savePath' => ...);
 */
 static protected function getProviderDataItem(array $useChannel, $secretTextItem)
 {
 $args = microtime(true) . '_secret_length_' . strlen($secretTextItem)
 . '_' . implode('_', $useChannel);
 
 $result =  array(
 'path'      => self::$optionsCoverText['path'],
 'savePath'  => self::$stegoPath . '/' . sprintf(self::$optionsCoverText['savePath'], $args)
 );
 
 return $result;
 }
 
 /**
 * Gets random channel
 *
 * @return array
 */
 static protected function getRandomChannel(array $channel, $channelSize = null)
 {
 $channelSize    = $channelSize ? : count($channel);
 $useChannelSize = mt_rand(1, $channelSize);
 $useChannelKey  = (array)array_rand($channel, $useChannelSize);
 
 $result = [];
 foreach($useChannelKey as $value) {
 $result[] = $channel[$value];
 }
 
 return $result;
 }
 
 static protected function getRandomText($text, $textLength = null)
 {
 $textLength = $textLength ? : strlen($text);
 $itemStart  = mt_rand(0, $textLength - 1);
 $itemLength = mt_rand(1, $textLength);
 
 $result = substr($text, $itemStart, $itemLength);
 
 return str_shuffle($result);
 }
 }
 |