Repository: kleiram/transmission-php Branch: master Commit: 3a9da015251a Files: 38 Total size: 112.0 KB Directory structure: gitextract_kh88jjkg/ ├── .gitignore ├── .travis.yml ├── CHANGELOG ├── LICENSE ├── README.md ├── composer.json ├── examples/ │ └── queue.php ├── lib/ │ └── Transmission/ │ ├── Client.php │ ├── Model/ │ │ ├── AbstractModel.php │ │ ├── File.php │ │ ├── FreeSpace.php │ │ ├── ModelInterface.php │ │ ├── Peer.php │ │ ├── Session.php │ │ ├── Stats/ │ │ │ ├── Session.php │ │ │ └── Stats.php │ │ ├── Status.php │ │ ├── Torrent.php │ │ ├── Tracker.php │ │ └── TrackerStats.php │ ├── Transmission.php │ └── Util/ │ ├── PropertyMapper.php │ └── ResponseValidator.php ├── phpunit.xml.dist └── tests/ ├── Transmission/ │ ├── Mock/ │ │ └── Model.php │ └── Tests/ │ ├── ClientTest.php │ ├── Model/ │ │ ├── AbstractModelTest.php │ │ ├── FileTest.php │ │ ├── PeerTest.php │ │ ├── SessionTest.php │ │ ├── StatusTest.php │ │ ├── TorrentTest.php │ │ ├── TrackerStatsTest.php │ │ └── TrackerTest.php │ ├── TransmissionTest.php │ └── Util/ │ ├── PropertyMapperTest.php │ └── ResponseValidatorTest.php └── bootstrap.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ vendor/ composer.lock composer.phar phpunit.xml ================================================ FILE: .travis.yml ================================================ language: php php: [5.3, 5.4, 5.5] before_script: - composer install --dev --prefer-source script: phpunit --coverage-text ================================================ FILE: CHANGELOG ================================================ Version Changes 0.1.0 - Initial release 0.2.0 - Rewrote the entire public API 0.3.0 - Added support for authentication 0.4.0 - The library now requires at least PHP 5.3.2 - Added support for getting files downloaded by torrent - Added support for getting trackers used by a torrent - Added support for getting peers connected to - The torrent now contains: * Whether it is finished * The up- and download rate (in bytes/s) * The size of the download (when completed) * The ETA of the download * The percentage of the download completed - Made the authentication more flexible - The client now sends an User-Agent header with each request - Added support for starting, stopping, veryfing and requesting a reannounce of torrents 0.5.0 - Fix a bug in the authentication/authorization mechanism - A whole lot of other stuff including management of the Transmission session (setting global download speed limit and toggling the speed limit among others). ================================================ FILE: LICENSE ================================================ Copyright (c) 2014, Ramon Kleiss all(); // Getting a specific torrent from the download queue $torrent = $transmission->get(1); // (you can also get a torrent by the hash of the torrent) $torrent = $transmission->get(/* torrent hash */); // Adding a torrent to the download queue $torrent = $transmission->add(/* path to torrent */); // Removing a torrent from the download queue $torrent = $transmission->get(1); $transmission->remove($torrent); // Or if you want to delete all local data too $transmission->remove($torrent, true); // You can also get the Trackers that the torrent currently uses // These are instances of the Transmission\Model\Tracker class $trackers = $torrent->getTrackers(); // You can also get the Trackers statistics and info that the torrent currently has // These are instances of the Transmission\Model\trackerStats class $trackerStats = $torrent->getTrackerStats(); // To get the start date/time of the torrent in UNIX Timestamp format $startTime = $torrent -> getStartDate(); // To get the number of peers connected $connectedPeers = $torrent -> getPeersConnected(); // Getting the files downloaded by the torrent are available too // These are instances of Transmission\Model\File $files = $torrent->getFiles(); // You can start, stop, verify the torrent and ask the tracker for // more peers to connect to $transmission->stop($torrent); $transmission->start($torrent); $transmission->start($torrent, true); // Pass true if you want to start the torrent immediatly $transmission->verify($torrent); $transmission->reannounce($torrent); ``` To find out which information is contained by the torrent, check [`Transmission\Model\Torrent`](https://github.com/kleiram/transmission-php/tree/master/lib/Transmission/Model/Torrent.php). By default, the library will try to connect to `localhost:9091`. If you want to connect to another host or post you can pass those to the constructor of the `Transmission` class: ```php all(); $torrent = $transmission->get(1); $torrent = $transmission->add(/* path to torrent */); // When you already have a torrent, you don't have to pass the client again $torrent->delete(); ``` It is also possible to pass the torrent data directly instead of using a file but the metadata must be base64-encoded: ```php add(/* base64-encoded metainfo */, true); ``` If the Transmission server is secured with a username and password you can authenticate using the `Client` class: ```php authenticate('username', 'password'); $transmission = new Transmission(); $transmission->setClient($client); ``` Additionally, you can control the actual Transmission setting. This means you can modify the global download limit or change the download directory: ```php getSession(); $session->setDownloadDir('/home/foo/downloads/complete'); $session->setIncompleteDir('/home/foo/downloads/incomplete'); $session->setIncompleteDirEnabled(true); $session->save(); ``` ## Testing Testing is done using [PHPUnit](https://github.com/sebastianbergmann/phpunit). To test the application, you have to install the dependencies using Composer before running the tests: ```bash $ curl -s https://getcomposer.org/installer | php $ php composer.phar install $ phpunit --coverage-text ``` ## Integration into frameworks Currently, there's a [Symfony](https://github.com/chellem/TransmissionBundle) bundle in development which allows you to easily use this library within Symfony. ## Changelog Version Changes 0.1.0 - Initial release 0.2.0 - Rewrote the entire public API 0.3.0 - Added support for authentication 0.4.0 - The library now requires at least PHP 5.3.2 - Added support for getting files downloaded by torrent - Added support for getting trackers used by a torrent - Added support for getting peers connected to - The torrent now contains: * Whether it is finished * The up- and download rate (in bytes/s) * The size of the download (when completed) * The ETA of the download * The percentage of the download completed - Made the authentication more flexible - The client now sends an User-Agent header with each request - Added support for starting, stopping, veryfing and requesting a reannounce of torrents 0.5.0 - Fix a bug in the authentication/authorization mechanism - A whole lot of other stuff including management of the Transmission session (setting global download speed limit and toggling the speed limit among others). ## License This library is licensed under the BSD 2-clause license. Copyright (c) 2014, Ramon Kleiss All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. ================================================ FILE: composer.json ================================================ { "name": "kleiram/transmission-php", "description": "PHP Transmission client", "keywords": ["transmission", "torrent", "download"], "type": "library", "license": "BSD-2-Clause", "authors": [ { "name": "Ramon Kleiss", "email": "ramon@cubilon.nl" } ], "require": { "kriswallsmith/buzz": ">=0.9", "symfony/property-access": ">=2.2.1" }, "autoload": { "psr-0": { "Transmission": "lib/" } } } ================================================ FILE: examples/queue.php ================================================ all(); echo "Downloading to: {$transmission->getSession()->getDownloadDir()}\n"; foreach ($queue as $torrent) { echo "{$torrent->getName()}"; if ($torrent->isFinished()) { echo ": done\n"; } else { if ($torrent->isDownloading()) { echo ": {$torrent->getPercentDone()}% "; echo "(eta: ". gmdate("H:i:s", $torrent->getEta()) .")\n"; } else { echo ": paused\n"; } } } ================================================ FILE: lib/Transmission/Client.php ================================================ */ class Client { /** * @var string */ const DEFAULT_HOST = 'localhost'; /** * @var integer */ const DEFAULT_PORT = 9091; /** * @var string */ const DEFAULT_PATH = '/transmission/rpc'; /** * @var string */ const TOKEN_HEADER = 'X-Transmission-Session-Id'; /** * @var string */ protected $host = self::DEFAULT_HOST; /** * @var integer */ protected $port = self::DEFAULT_PORT; /** * @var string */ protected $path = self::DEFAULT_PATH; /** * @var string */ protected $token; /** * @var ClientInterface */ protected $client; /** * @var string */ protected $auth; /** * Constructor * * @param string $host The hostname of the Transmission server * @param integer $port The port the Transmission server is listening on * @param string $path The path to Transmission server rpc api */ public function __construct($host = null, $port = null, $path = null) { $this->token = null; $this->client = new Curl(); if ($host) $this->setHost($host); if ($port) $this->setPort($port); if ($path) $this->setPath($path); } /** * Authenticate against the Transmission server * * @param string $username * @param string $password */ public function authenticate($username, $password) { $this->auth = base64_encode($username .':'. $password); } /** * Make an API call * * @param string $method * @param array $arguments * @return \stdClass * @throws \RuntimeException */ public function call($method, array $arguments) { list($request, $response) = $this->compose($method, $arguments); try { $this->getClient()->send($request, $response); } catch (\Exception $e) { throw new \RuntimeException( 'Could not connect to Transmission', 0, $e ); } return $this->validateResponse($response, $method, $arguments); } /** * Get the URL used to connect to Transmission * * @return string */ public function getUrl() { return sprintf( 'http://%s:%d', $this->getHost(), $this->getPort() ); } /** * Set the hostname of the Transmission server * * @param string $host */ public function setHost($host) { $this->host = (string) $host; } /** * Get the hostname of the Transmission server * * @return string */ public function getHost() { return $this->host; } /** * Set the port the Transmission server is listening on * * @param integer $port */ public function setPort($port) { $this->port = (integer) $port; } /** * Get the port the Transmission server is listening on * * @return integer */ public function getPort() { return $this->port; } /** * Set the path to Transmission server rpc api * * @param string $path */ public function setPath($path) { return $this->path = (string) $path; } /** * Get the path to Transmission server rpc api */ public function getPath() { return $this->path; } /** * Set the CSRF-token of the Transmission client * * @param string $token */ public function setToken($token) { $this->token = (string) $token; } /** * Get the CSRF-token for the Transmission client * * @return string */ public function getToken() { return $this->token; } /** * Set the Buzz client used to connect to Transmission * * @param ClientInterface $client */ public function setClient(ClientInterface $client) { $this->client = $client; } /** * Get the Buzz client used to connect to Transmission * * @return ClientInterface */ public function getClient() { return $this->client; } /** * @param string $method * @param array $arguments * @return array|Request[]|Response[] */ protected function compose($method, $arguments) { $request = new Request('POST', $this->getPath(), $this->getUrl()); $request->addHeader(sprintf('%s: %s', self::TOKEN_HEADER, $this->getToken())); $request->setContent(json_encode(array( 'method' => $method, 'arguments' => $arguments ))); if (is_string($this->auth)) { $request->addHeader(sprintf('Authorization: Basic %s', $this->auth)); } return array($request, new Response()); } /** * @param Response $response * @param string $method * @param array $arguments * @return \stdClass * @throws \RuntimeException */ protected function validateResponse($response, $method, $arguments) { if (!in_array($response->getStatusCode(), array(200, 401, 409))) { throw new \RuntimeException('Unexpected response received from Transmission'); } if ($response->getStatusCode() == 401) { throw new \RuntimeException('Access to Transmission requires authentication'); } if ($response->getStatusCode() == 409) { $this->setToken($response->getHeader(self::TOKEN_HEADER)); return $this->call($method, $arguments); } return json_decode($response->getContent()); } } ================================================ FILE: lib/Transmission/Model/AbstractModel.php ================================================ */ abstract class AbstractModel implements ModelInterface { /** * @var Client */ protected $client; /** * Constructor * * @param Client $client */ public function __construct(Client $client = null) { $this->client = $client; } /** * @param Client $client */ public function setClient(Client $client) { $this->client = $client; } /** * @return Client */ public function getClient() { return $this->client; } /** * {@inheritDoc} */ public static function getMapping() { return array(); } /** * @param string $method * @param array $arguments */ protected function call($method, $arguments) { if ($this->client) { ResponseValidator::validate( $method, $this->client->call($method, $arguments) ); } } } ================================================ FILE: lib/Transmission/Model/File.php ================================================ */ class File extends AbstractModel { /** * @var string */ protected $name; /** * @var integer */ protected $size; /** * @var integer */ protected $completed; /** * @param string $name */ public function setName($name) { $this->name = (string) $name; } /** * @return string */ public function getName() { return $this->name; } /** * @param integer $size */ public function setSize($size) { $this->size = (integer) $size; } /** * @return integer */ public function getSize() { return $this->size; } /** * @param integer $size */ public function setCompleted($completed) { $this->completed = (integer) $completed; } /** * @return integer */ public function getCompleted() { return $this->completed; } /** * @return boolean */ public function isDone() { return $this->getSize() == $this->getCompleted(); } /** * {@inheritDoc} */ public static function getMapping() { return array( 'name' => 'name', 'length' => 'size', 'bytesCompleted' => 'completed' ); } public function __toString() { return $this->name; } } ================================================ FILE: lib/Transmission/Model/FreeSpace.php ================================================ path; } /** * Sets the value of path. * * @param string $path the path */ public function setPath($path) { $this->path = $path; } /** * Gets the value of size. * * @return integer */ public function getSize() { return $this->size; } /** * Sets the value of size. * * @param integer $size the size */ public function setSize($size) { $this->size = $size; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'path' => 'path', 'size-bytes' => 'size', ); } } ================================================ FILE: lib/Transmission/Model/ModelInterface.php ================================================ */ interface ModelInterface { /** * Get the mapping of the model * * @return array */ public static function getMapping(); } ================================================ FILE: lib/Transmission/Model/Peer.php ================================================ */ class Peer extends AbstractModel { /** * @var string */ protected $address; /** * @var integer */ protected $port; /** * @var string */ protected $clientName; /** * @var boolean */ protected $clientChoked; /** * @var boolean */ protected $clientInterested; /** * @var boolean */ protected $downloading; /** * @var boolean */ protected $encrypted; /** * @var boolean */ protected $incoming; /** * @var boolean */ protected $uploading; /** * @var boolean */ protected $utp; /** * @var boolean */ protected $peerChoked; /** * @var boolean */ protected $peerInterested; /** * @var double */ protected $progress; /** * @var integer */ protected $uploadRate; /** * @var integer */ protected $downloadRate; /** * @param string $address */ public function setAddress($address) { $this->address = (string) $address; } /** * @return string */ public function getAddress() { return $this->address; } /** * @param integer $port */ public function setPort($port) { $this->port = (integer) $port; } /** * @return integer */ public function getPort() { return $this->port; } /** * @param string $clientName */ public function setClientName($clientName) { $this->clientName = (string) $clientName; } /** * @return string */ public function getClientName() { return $this->clientName; } /** * @param boolean $choked */ public function setClientChoked($choked) { $this->clientChoked = (boolean) $choked; } /** * @return boolean */ public function isClientChoked() { return $this->clientChoked; } /** * @param boolean $interested */ public function setClientInterested($interested) { $this->clientInterested = (boolean) $interested; } /** * @return boolean */ public function isClientInterested() { return $this->clientInterested; } /** * @param boolean $downloading */ public function setDownloading($downloading) { $this->downloading = (boolean) $downloading; } /** * @return boolean */ public function isDownloading() { return $this->downloading; } /** * @param boolean $encrypted */ public function setEncrypted($encrypted) { $this->encrypted = (boolean) $encrypted; } /** * @return boolean */ public function isEncrypted() { return $this->encrypted; } /** * @param boolean $incoming */ public function setIncoming($incoming) { $this->incoming = (boolean) $incoming; } /** * @return boolean */ public function isIncoming() { return $this->incoming; } /** * @param boolean $uploading */ public function setUploading($uploading) { $this->uploading = (boolean) $uploading; } /** * @return boolean */ public function isUploading() { return $this->uploading; } /** * @param boolean $utp */ public function setUtp($utp) { $this->utp = (boolean) $utp; } /** * @return boolean */ public function isUtp() { return $this->utp; } /** * @param boolean $choked */ public function setPeerChoked($choked) { $this->peerChoked = (boolean) $choked; } /** * @return boolean */ public function isPeerChoked() { return $this->peerChoked; } /** * @param boolean $interested */ public function setPeerInterested($interested) { $this->peerInterested = (boolean) $interested; } /** * @return boolean */ public function isPeerInterested() { return $this->peerInterested; } /** * @param double $progress */ public function setProgress($progress) { $this->progress = (double) $progress; } /** * @return double */ public function getProgress() { return $this->progress; } /** * @param integer $rate */ public function setUploadRate($rate) { $this->uploadRate = (integer) $rate; } /** * @return integer */ public function getUploadRate() { return $this->uploadRate; } /** * @param integer $rate */ public function setDownloadRate($rate) { $this->downloadRate = (integer) $rate; } /** * @return integer */ public function getDownloadRate() { return $this->downloadRate; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'address' => 'address', 'port' => 'port', 'clientName' => 'clientName', 'clientIsChoked' => 'clientChoked', 'clientIsInterested' => 'clientInterested', 'isDownloadingFrom' => 'downloading', 'isEncrypted' => 'encrypted', 'isIncoming' => 'incoming', 'isUploadingTo' => 'uploading', 'isUTP' => 'utp', 'peerIsChoked' => 'peerChoked', 'peerIsInterested' => 'peerInterested', 'progress' => 'progress', 'rateToClient' => 'uploadRate', 'rateFromClient' => 'downloadRate' ); } } ================================================ FILE: lib/Transmission/Model/Session.php ================================================ */ class Session extends AbstractModel { /** * @var integer */ protected $altSpeedDown; /** * @var boolean */ protected $altSpeedEnabled; /** * @var string */ protected $downloadDir; /** * @var boolean */ protected $downloadQueueEnabled; /** * @var integer */ protected $downloadQueueSize; /** * @var string */ protected $incompleteDir; /** * @var boolean */ protected $incompleteDirEnabled; /** * @var string */ protected $torrentDoneScript; /** * @var boolean */ protected $torrentDoneScriptEnabled; /** * @var double */ protected $seedRatioLimit; /** * @var boolean */ protected $seedRatioLimited; /** * @var integer */ protected $seedQueueSize; /** * @var boolean */ protected $seedQueueEnabled; /** * @var integer */ protected $downloadSpeedLimit; /** * @var boolean */ protected $downloadSpeedLimitEnabled; /** * @var integer */ protected $uploadSpeedLimit; /** * @var boolean */ protected $uploadSpeedLimitEnabled; /** * @param integer $speed */ public function setAltSpeedDown($speed) { $this->altSpeedDown = (integer) $speed; } /** * @return integer */ public function getAltSpeedDown() { return $this->altSpeedDown; } /** * @param boolean $enabled */ public function setAltSpeedEnabled($enabled) { $this->altSpeedEnabled = (boolean) $enabled; } /** * @return boolean */ public function isAltSpeedEnabled() { return $this->altSpeedEnabled; } /** * @param string $downloadDir */ public function setDownloadDir($downloadDir) { $this->downloadDir = (string) $downloadDir; } /** * @return string */ public function getDownloadDir() { return $this->downloadDir; } /** * @param boolean $enabled */ public function setDownloadQueueEnabled($enabled) { $this->downloadQueueEnabled = (boolean) $enabled; } /** * @return boolean */ public function isDownloadQueueEnabled() { return $this->downloadQueueEnabled; } /** * @param integer $size */ public function setDownloadQueueSize($size) { $this->downloadQueueSize = (integer) $size; } /** * @return integer */ public function getDownloadQueueSize() { return $this->downloadQueueSize; } /** * @param string $directory */ public function setIncompleteDir($directory) { $this->incompleteDir = (string) $directory; } /** * @return string */ public function getIncompleteDir() { return $this->incompleteDir; } /** * @param boolean $enabled */ public function setIncompleteDirEnabled($enabled) { $this->incompleteDirEnabled = (boolean) $enabled; } /** * @return boolean */ public function isIncompleteDirEnabled() { return $this->incompleteDirEnabled; } /** * @param string $filename */ public function setTorrentDoneScript($filename) { $this->torrentDoneScript = (string) $filename; } /** * @return string */ public function getTorrentDoneScript() { return $this->torrentDoneScript; } /** * @param boolean $enabled */ public function setTorrentDoneScriptEnabled($enabled) { $this->torrentDoneScriptEnabled = (boolean) $enabled; } /** * @return boolean */ public function isTorrentDoneScriptEnabled() { return $this->torrentDoneScriptEnabled; } /** * @param double $limit */ public function setSeedRatioLimit($limit) { $this->seedRatioLimit = (double) $limit; } /** * @return double */ public function getSeedRatioLimit() { return $this->seedRatioLimit; } /** * @param boolean $limited */ public function setSeedRatioLimited($limited) { $this->seedRatioLimited = (boolean) $limited; } /** * @return boolean */ public function isSeedRatioLimited() { return $this->seedRatioLimited; } /** * @param integer $size */ public function setSeedQueueSize($size) { $this->seedQueueSize = (integer) $size; } /** * @return integer */ public function getSeedQueueSize() { return $this->seedQueueSize; } /** * @param boolean $enabled */ public function setSeedQueueEnabled($enabled) { $this->seedQueueEnabled = (boolean) $enabled; } /** * @return boolean */ public function isSeedQueueEnabled() { return $this->seedQueueEnabled; } /** * @param integer $limit */ public function setDownloadSpeedLimit($limit) { $this->downloadSpeedLimit = (integer) $limit; } /** * @return integer */ public function getDownloadSpeedLimit() { return $this->downloadSpeedLimit; } /** * @param boolean $enabled */ public function setDownloadSpeedLimitEnabled($enabled) { $this->downloadSpeedLimitEnabled = (boolean) $enabled; } /** * @return boolean */ public function isDownloadSpeedLimitEnabled() { return $this->downloadSpeedLimitEnabled; } /** * @param integer $limit */ public function setUploadSpeedLimit($limit) { $this->uploadSpeedLimit = (integer) $limit; } /** * @return integer */ public function getUploadSpeedLimit() { return $this->uploadSpeedLimit; } /** * @param boolean $enabled */ public function setUploadSpeedLimitEnabled($enabled) { $this->uploadSpeedLimitEnabled = (boolean) $enabled; } /** * @return boolean */ public function isUploadSpeedLimitEnabled() { return $this->uploadSpeedLimitEnabled; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'alt-speed-down' => 'altSpeedDown', 'alt-speed-enabled' => 'altSpeedEnabled', 'download-dir' => 'downloadDir', 'download-queue-enabled' => 'downloadQueueEnabled', 'download-queue-size' => 'downloadQueueSize', 'incomplete-dir' => 'incompleteDir', 'incomplete-dir-enabled' => 'incompleteDirEnabled', 'script-torrent-done-filename' => 'torrentDoneScript', 'script-torrent-done-enabled' => 'torrentDoneScriptEnabled', 'seedRatioLimit' => 'seedRatioLimit', 'seedRatioLimited' => 'seedRatioLimited', 'seed-queue-size' => 'seedQueueSize', 'seed-queue-enabled' => 'seedQueueEnabled', 'speed-limit-down' => 'downloadSpeedLimit', 'speed-limit-down-enabled' => 'downloadSpeedLimitEnabled', 'speed-limit-up' => 'uploadSpeedLimit', 'speed-limit-up-enabled' => 'uploadSpeedLimitEnabled', ); } public function save() { $arguments = array(); foreach ($this->getMapping() as $key => $value) { $arguments[$key] = $this->{$value}; } if (!empty($arguments) && $this->getClient()) { ResponseValidator::validate( 'session-set', $this->getClient()->call('session-set', $arguments) ); } } } ================================================ FILE: lib/Transmission/Model/Stats/Session.php ================================================ activeTorrentCount; } /** * Sets the value of activeTorrentCount. * * @param integer $activeTorrentCount the active torrent count */ public function setActiveTorrentCount($activeTorrentCount) { $this->activeTorrentCount = $activeTorrentCount; } /** * Gets the value of downloadSpeed. * * @return integer */ public function getDownloadSpeed() { return $this->downloadSpeed; } /** * Sets the value of downloadSpeed. * * @param integer $downloadSpeed the download speed */ public function setDownloadSpeed($downloadSpeed) { $this->downloadSpeed = $downloadSpeed; } /** * Gets the value of pausedTorrentCount. * * @return integer */ public function getPausedTorrentCount() { return $this->pausedTorrentCount; } /** * Sets the value of pausedTorrentCount. * * @param integer $pausedTorrentCount the paused torrent count */ public function setPausedTorrentCount($pausedTorrentCount) { $this->pausedTorrentCount = $pausedTorrentCount; } /** * Gets the value of torrentCount. * * @return integer */ public function getTorrentCount() { return $this->torrentCount; } /** * Sets the value of torrentCount. * * @param integer $torrentCount the torrent count */ public function setTorrentCount($torrentCount) { $this->torrentCount = $torrentCount; } /** * Gets the value of uploadSpeed. * * @return integer */ public function getUploadSpeed() { return $this->uploadSpeed; } /** * Sets the value of uploadSpeed. * * @param integer $uploadSpeed the upload speed */ public function setUploadSpeed($uploadSpeed) { $this->uploadSpeed = $uploadSpeed; } /** * Gets the value of cumulative. * * @return Stats */ public function getCumulative() { return $this->cumulative; } /** * Sets the value of cumulative. * * @param Stats $cumulative the cumulative */ public function setCumulative(Stats $cumulative) { $this->cumulative = $cumulative; } /** * Gets the value of current. * * @return Stats */ public function getCurrent() { return $this->current; } /** * Sets the value of current. * * @param Stats $current the current */ public function setCurrent(Stats $current) { $this->current = $current; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'activeTorrentCount' => 'activeTorrentCount', 'downloadSpeed' => 'downloadSpeed', 'pausedTorrentCount' => 'pausedTorrentCount', 'torrentCount' => 'torrentCount', 'uploadSpeed' => 'uploadSpeed', 'cumulative-stats'=>'cumulative', 'current-stats' => 'current', ); } } ================================================ FILE: lib/Transmission/Model/Stats/Stats.php ================================================ downloadedBytes; } /** * Sets the value of downloadedBytes. * * @param integer $downloadedBytes the downloaded bytes */ public function setDownloadedBytes($downloadedBytes) { $this->downloadedBytes = $downloadedBytes; } /** * Gets the value of filesAdded. * * @return integer */ public function getFilesAdded() { return $this->filesAdded; } /** * Sets the value of filesAdded. * * @param integer $filesAdded the files added */ public function setFilesAdded($filesAdded) { $this->filesAdded = $filesAdded; } /** * Gets the value of secondsActive. * * @return integer */ public function getSecondsActive() { return $this->secondsActive; } /** * Sets the value of secondsActive. * * @param integer $secondsActive the seconds active */ public function setSecondsActive($secondsActive) { $this->secondsActive = $secondsActive; } /** * Gets the value of sessionCount. * * @return integer */ public function getSessionCount() { return $this->sessionCount; } /** * Sets the value of sessionCount. * * @param integer $sessionCount the session count */ public function setSessionCount($sessionCount) { $this->sessionCount = $sessionCount; } /** * Gets the value of uploadedBytes. * * @return integer */ public function getUploadedBytes() { return $this->uploadedBytes; } /** * Sets the value of uploadedBytes. * * @param integer $uploadedBytes the uploaded bytes */ public function setUploadedBytes($uploadedBytes) { $this->uploadedBytes = $uploadedBytes; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'downloadedBytes' => 'downloadedBytes', 'filesAdded' => 'filesAdded', 'secondsActive' => 'secondsActive', 'sessionCount' => 'sessionCount', 'uploadedBytes' => 'uploadedBytes' ); } } ================================================ FILE: lib/Transmission/Model/Status.php ================================================ */ class Status extends AbstractModel { /** * @var integer */ const STATUS_STOPPED = 0; /** * @var integer */ const STATUS_CHECK_WAIT = 1; /** * @var integer */ const STATUS_CHECK = 2; /** * @var integer */ const STATUS_DOWNLOAD_WAIT = 3; /** * @var integer */ const STATUS_DOWNLOAD = 4; /** * @var integer */ const STATUS_SEED_WAIT = 5; /** * @var integer */ const STATUS_SEED = 6; /** * @var integer */ protected $status; /** * @param integer|Status $status */ public function __construct($status) { if ($status instanceof self) { $this->status = $status->getValue(); } else { $this->status = (integer) $status; } } /** * @return integer */ public function getValue() { return $this->status; } /** * @return boolean */ public function isStopped() { return $this->status == self::STATUS_STOPPED; } /** * @return boolean */ public function isChecking() { return ($this->status == self::STATUS_CHECK || $this->status == self::STATUS_CHECK_WAIT); } /** * @return boolean */ public function isDownloading() { return ($this->status == self::STATUS_DOWNLOAD || $this->status == self::STATUS_DOWNLOAD_WAIT); } /** * @return boolean */ public function isSeeding() { return ($this->status == self::STATUS_SEED || $this->status == self::STATUS_SEED_WAIT); } } ================================================ FILE: lib/Transmission/Model/Torrent.php ================================================ */ class Torrent extends AbstractModel { /** * @var integer */ protected $id; /** * @var integer */ protected $eta; /** * @var integer */ protected $size; /** * @var string */ protected $name; /** * @var string */ protected $hash; /** * @var Status */ protected $status; /** * @var boolean */ protected $finished; /** * @var integer */ protected $startDate; /** * @var integer */ protected $uploadRate; /** * @var integer */ protected $downloadRate; /** * @var integer */ protected $peersConnected; /** * @var double */ protected $percentDone; /** * @var array */ protected $files = array(); /** * @var array */ protected $peers = array(); /** * @var array */ protected $trackers = array(); /** * @var array */ protected $trackerStats = array(); /** * @var double */ protected $uploadRatio; /** * @var string */ protected $downloadDir; /** * @var integer */ protected $downloadedEver; /** * @var integer */ protected $uploadedEver; /** * @param integer $id */ public function setId($id) { $this->id = (integer) $id; } /** * @return integer */ public function getId() { return $this->id; } /** * @param integer $eta */ public function setEta($eta) { $this->eta = (integer) $eta; } /** * @return integer */ public function getEta() { return $this->eta; } /** * @param integer $size */ public function setSize($size) { $this->size = (integer) $size; } /** * @return integer */ public function getSize() { return $this->size; } /** * @param string $name */ public function setName($name) { $this->name = (string) $name; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $hash */ public function setHash($hash) { $this->hash = (string) $hash; } /** * @return string */ public function getHash() { return $this->hash; } /** * @param integer|Status $status */ public function setStatus($status) { $this->status = new Status($status); } /** * @return integer */ public function getStatus() { return $this->status->getValue(); } /** * @param boolean $finished */ public function setFinished($finished) { $this->finished = (boolean) $finished; } /** * @return boolean */ public function isFinished() { return ($this->finished || (int) $this->getPercentDone() == 100); } /** * @var integer $startDate */ public function setStartDate($startDate) { $this->startDate = (integer) $startDate; } /** * @return integer */ public function getStartDate() { return $this->startDate; } /** * @var integer $rate */ public function setUploadRate($rate) { $this->uploadRate = (integer) $rate; } /** * @return integer */ public function getUploadRate() { return $this->uploadRate; } /** * @param integer $rate */ public function setDownloadRate($rate) { $this->downloadRate = (integer) $rate; } /** * @param integer $peersConnected */ public function setPeersConnected($peersConnected) { $this->peersConnected = (integer) $peersConnected; } /** * @return integer */ public function getPeersConnected() { return $this->peersConnected; } /** * @return integer */ public function getDownloadRate() { return $this->downloadRate; } /** * @param double $done */ public function setPercentDone($done) { $this->percentDone = (double) $done; } /** * @return double */ public function getPercentDone() { return $this->percentDone * 100.0; } /** * @param array $files */ public function setFiles(array $files) { $this->files = array_map(function ($file) { return PropertyMapper::map(new File(), $file); }, $files); } /** * @return array */ public function getFiles() { return $this->files; } /** * @param array $peers */ public function setPeers(array $peers) { $this->peers = array_map(function ($peer) { return PropertyMapper::map(new Peer(), $peer); }, $peers); } /** * @return array */ public function getPeers() { return $this->peers; } /** * @param array $trackerStats */ public function setTrackerStats(array $trackerStats) { $this->trackerStats = array_map(function ($trackerStats) { return PropertyMapper::map(new TrackerStats(), $trackerStats); }, $trackerStats); } /** * @return array */ public function getTrackerStats() { return $this->trackerStats; } /** * @param array $trackers */ public function setTrackers(array $trackers) { $this->trackers = array_map(function ($tracker) { return PropertyMapper::map(new Tracker(), $tracker); }, $trackers); } /** * @return array */ public function getTrackers() { return $this->trackers; } /** * @param double $ratio */ public function setUploadRatio($ratio) { $this->uploadRatio = (double) $ratio; } /** * @return double */ public function getUploadRatio() { return $this->uploadRatio; } /** * @return boolean */ public function isStopped() { return $this->status->isStopped(); } /** * @return boolean */ public function isChecking() { return $this->status->isChecking(); } /** * @return boolean */ public function isDownloading() { return $this->status->isDownloading(); } /** * @return boolean */ public function isSeeding() { return $this->status->isSeeding(); } /** * @return string */ public function getDownloadDir() { return $this->downloadDir; } /** * @param string $downloadDir */ public function setDownloadDir($downloadDir) { $this->downloadDir = $downloadDir; } /** * @return int */ public function getDownloadedEver() { return $this->downloadedEver; } /** * @param int $downloadedEver */ public function setDownloadedEver($downloadedEver) { $this->downloadedEver = $downloadedEver; } /** * @return int */ public function getUploadedEver() { return $this->uploadedEver; } /** * @param int $uploadedEver */ public function setUploadedEver($uploadedEver) { $this->uploadedEver = $uploadedEver; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'id' => 'id', 'eta' => 'eta', 'sizeWhenDone' => 'size', 'name' => 'name', 'status' => 'status', 'isFinished' => 'finished', 'rateUpload' => 'uploadRate', 'rateDownload' => 'downloadRate', 'percentDone' => 'percentDone', 'files' => 'files', 'peers' => 'peers', 'peersConnected' => 'peersConnected', 'trackers' => 'trackers', 'trackerStats' => 'trackerStats', 'startDate' => 'startDate', 'uploadRatio' => 'uploadRatio', 'hashString' => 'hash', 'downloadDir' => 'downloadDir', 'downloadedEver' => 'downloadedEver', 'uploadedEver' => 'uploadedEver' ); } } ================================================ FILE: lib/Transmission/Model/Tracker.php ================================================ */ class Tracker extends AbstractModel { /** * @var integer */ protected $id; /** * @var integer */ protected $tier; /** * @var string */ protected $scrape; /** * @var string */ protected $announce; /** * @param integer $id */ public function setId($id) { $this->id = (integer) $id; } /** * @return integer */ public function getId() { return $this->id; } /** * @param integer $tier */ public function setTier($tier) { $this->tier = (integer) $tier; } /** * @return integer */ public function getTier() { return $this->tier; } /** * @param string $scrape */ public function setScrape($scrape) { $this->scrape = (string) $scrape; } /** * @return string */ public function getScrape() { return $this->scrape; } /** * @param string $announce */ public function setAnnounce($announce) { $this->announce = (string) $announce; } /** * @return string */ public function getAnnounce() { return $this->announce; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'id' => 'id', 'tier' => 'tier', 'scrape' => 'scrape', 'announce' => 'announce' ); } } ================================================ FILE: lib/Transmission/Model/TrackerStats.php ================================================ */ class TrackerStats extends AbstractModel { /** * @var string */ protected $host; /** * @var integer */ protected $leecherCount; /** * @var integer */ protected $seederCount; /** * @var string */ protected $lastAnnounceResult; /** * @var string */ protected $lastScrapeResult; /** * @param string $host */ public function setHost($host) { $this->host = (string) $host; } /** * @return string */ public function getHost() { return $this->host; } /** * @param string $lastAnnounceResult */ public function setLastAnnounceResult($lastAnnounceResult) { $this->lastAnnounceResult = (string) $lastAnnounceResult; } /** * @return string */ public function getLastAnnounceResult() { return $this->lastAnnounceResult; } /** * @param string $lastScrapeResult */ public function setLastScrapeResult($lastScrapeResult) { $this->lastScrapeResult = (string) $lastScrapeResult; } /** * @return string */ public function getLastScrapeResult() { return $this->lastScrapeResult; } /** * @param integer $seederCount */ public function setSeederCount($seederCount) { $this->seederCount = (integer) $seederCount; } /** * @return integer */ public function getSeederCount() { return $this->seederCount; } /** * @param integer $leecherCount */ public function setLeecherCount($leecherCount) { $this->leecherCount = (integer) $leecherCount; } /** * @return integer */ public function getLeecherCount() { return $this->leecherCount; } /** * {@inheritDoc} */ public static function getMapping() { return array( 'host' => 'host', 'leecherCount' => 'leecherCount', 'seederCount' => 'seederCount', 'lastScrapeResult' => 'lastScrapeResult', 'lastAnnounceResult' => 'lastAnnounceResult' ); } } ================================================ FILE: lib/Transmission/Transmission.php ================================================ */ class Transmission { /** * @var Client */ protected $client; /** * @var ResponseValidator */ protected $validator; /** * @var PropertyMapper */ protected $mapper; /** * Constructor * * @param string $host * @param integer $port * @param string $path */ public function __construct($host = null, $port = null, $path = null) { $this->setClient(new Client($host, $port, $path)); $this->setMapper(new PropertyMapper()); $this->setValidator(new ResponseValidator()); } /** * Get all the torrents in the download queue * * @return Torrent[] */ public function all() { $client = $this->getClient(); $mapper = $this->getMapper(); $response = $this->getClient()->call( 'torrent-get', array('fields' => array_keys(Torrent::getMapping())) ); $torrents = array_map(function ($data) use ($mapper, $client) { return $mapper->map( new Torrent($client), $data ); }, $this->getValidator()->validate('torrent-get', $response)); return $torrents; } /** * Get a specific torrent from the download queue * * @param integer $id * @return Torrent * @throws \RuntimeException */ public function get($id) { $client = $this->getClient(); $mapper = $this->getMapper(); $response = $this->getClient()->call('torrent-get', array( 'fields' => array_keys(Torrent::getMapping()), 'ids' => array($id) )); $torrent = array_reduce( $this->getValidator()->validate('torrent-get', $response), function ($torrent, $data) use ($mapper, $client) { return $torrent ? $torrent : $mapper->map(new Torrent($client), $data); }); if (!$torrent instanceof Torrent) { throw new \RuntimeException(sprintf("Torrent with ID %s not found", $id)); } return $torrent; } /** * Get the Transmission session * * @return Session */ public function getSession() { $response = $this->getClient()->call( 'session-get', array() ); return $this->getMapper()->map( new Session($this->getClient()), $this->getValidator()->validate('session-get', $response) ); } /** * @return SessionStats */ public function getSessionStats() { $response = $this->getClient()->call( 'session-stats', array() ); return $this->getMapper()->map( new SessionStats(), $this->getValidator()->validate('session-stats', $response) ); } /** * Get Free space * @param string $path * @return FreeSpace */ public function getFreeSpace($path=null) { if (!$path) { $path = $this->getSession()->getDownloadDir(); } $response = $this->getClient()->call( 'free-space', array('path'=>$path) ); return $this->getMapper()->map( new FreeSpace(), $this->getValidator()->validate('free-space', $response) ); } /** * Add a torrent to the download queue * * @param string $torrent * @param boolean $metainfo * @param string $savepath * @return Torrent */ public function add($torrent, $metainfo = false, $savepath = null) { $parameters = array($metainfo ? 'metainfo' : 'filename' => $torrent); if ($savepath !== null) { $parameters['download-dir'] = (string) $savepath; } $response = $this->getClient()->call( 'torrent-add', $parameters ); return $this->getMapper()->map( new Torrent($this->getClient()), $this->getValidator()->validate('torrent-add', $response) ); } /** * Start the download of a torrent * * @param Torrent $torrent * @param bool $now */ public function start(Torrent $torrent, $now = false) { $this->getClient()->call( $now ? 'torrent-start-now' : 'torrent-start', array('ids' => array($torrent->getId())) ); } /** * Stop the download of a torrent * * @param Torrent $torrent */ public function stop(Torrent $torrent) { $this->getClient()->call( 'torrent-stop', array('ids' => array($torrent->getId())) ); } /** * Verify the download of a torrent * * @param Torrent $torrent */ public function verify(Torrent $torrent) { $this->getClient()->call( 'torrent-verify', array('ids' => array($torrent->getId())) ); } /** * Request a reannounce of a torrent * * @param Torrent $torrent */ public function reannounce(Torrent $torrent) { $this->getClient()->call( 'torrent-reannounce', array('ids' => array($torrent->getId())) ); } /** * Remove a torrent from the download queue * * @param Torrent $torrent */ public function remove(Torrent $torrent, $localData = false) { $arguments = array('ids' => array($torrent->getId())); if ($localData) { $arguments['delete-local-data'] = true; } $this->getClient()->call('torrent-remove', $arguments); } /** * Set the client used to connect to Transmission * * @param Client $client */ public function setClient(Client $client) { $this->client = $client; } /** * Get the client used to connect to Transmission * * @return Client */ public function getClient() { return $this->client; } /** * Set the hostname of the Transmission server * * @param string $host */ public function setHost($host) { $this->getClient()->setHost($host); } /** * Get the hostname of the Transmission server * * @return string */ public function getHost() { return $this->getClient()->getHost(); } /** * Set the port the Transmission server is listening on * * @param integer $port */ public function setPort($port) { $this->getClient()->setPort($port); } /** * Get the port the Transmission server is listening on * * @return integer */ public function getPort() { return $this->getClient()->getPort(); } /** * Set the mapper used to map responses from Transmission to models * * @param PropertyMapper $mapper */ public function setMapper(PropertyMapper $mapper) { $this->mapper = $mapper; } /** * Get the mapper used to map responses from Transmission to models * * @return PropertyMapper */ public function getMapper() { return $this->mapper; } /** * Set the validator used to validate Transmission responses * * @param ResponseValidator $validator */ public function setValidator(ResponseValidator $validator) { $this->validator = $validator; } /** * Get the validator used to validate Transmission responses * * @return ResponseValidator */ public function getValidator() { return $this->validator; } } ================================================ FILE: lib/Transmission/Util/PropertyMapper.php ================================================ */ class PropertyMapper { /** * @param ModelInterface $model * @param \stdClass $dto * @return ModelInterface */ public static function map(ModelInterface $model, $dto) { $accessor = PropertyAccess::createPropertyAccessor(); $mapping = array_filter($model->getMapping(), function ($value) { return !is_null($value); }); foreach ($mapping as $source => $dest) { try { $accessor->setValue( $model, $dest, $accessor->getValue($dto, $source) ); } catch (\Exception $e) { continue; } } return $model; } } ================================================ FILE: lib/Transmission/Util/ResponseValidator.php ================================================ */ class ResponseValidator { /** * @param string $method * @param \stdClass $response * @return \stdClass */ public static function validate($method, \stdClass $response) { if (!isset($response->result)) { throw new \RuntimeException('Invalid response received from Transmission'); } if (!in_array($response->result, array('success', 'duplicate torrent'))) { throw new \RuntimeException(sprintf( 'An error occured: "%s"', $response->result )); } switch ($method) { case 'torrent-get': return self::validateGetResponse($response); case 'torrent-add': return self::validateAddResponse($response); case 'session-get': return self::validateSessionGetResponse($response); case 'session-stats': return self::validateSessionStatsGetResponse($response); case 'free-space': return self::validateFreeSpaceGetResponse($response); } } /** * @param \stdClass $response * @throws \RuntimeException */ public static function validateGetResponse(\stdClass $response) { if (!isset($response->arguments) || !isset($response->arguments->torrents)) { throw new \RuntimeException( 'Invalid response received from Transmission' ); } return $response->arguments->torrents; } /** * @param \stdClass $response * @throws \RuntimeException */ public static function validateAddResponse(\stdClass $response) { $fields = array('torrent-added', 'torrent-duplicate'); foreach ($fields as $field) { if (isset($response->arguments) && isset($response->arguments->$field) && count($response->arguments->$field)) { return $response->arguments->$field; } } throw new \RuntimeException('Invalid response received from Transmission'); } public static function validateSessionGetResponse(\stdClass $response) { if (!isset($response->arguments)) { throw new \RuntimeException( 'Invalid response received from Transmission' ); } return $response->arguments; } /** * @param \stdClass $response * @return \stdClass */ public static function validateSessionStatsGetResponse(\stdClass $response) { if (!isset($response->arguments)) { throw new \RuntimeException( 'Invalid response received from Transmission' ); } $class='Transmission\\Model\\Stats\\Stats'; foreach (array('cumulative-stats','current-stats') as $property) { if (property_exists($response->arguments,$property)) { $instance=self::map($response->arguments->$property,$class); $response->arguments->$property=$instance; } } return $response->arguments; } private static function map($object,$class) { return PropertyMapper::map(new $class(),$object); } public static function validateFreeSpaceGetResponse(\stdClass $response) { if (!isset($response->arguments)) { throw new \RuntimeException( 'Invalid response received from Transmission' ); } return $response->arguments; } } ================================================ FILE: phpunit.xml.dist ================================================ ./tests/Transmission/ ./lib/Transmission/ ================================================ FILE: tests/Transmission/Mock/Model.php ================================================ fo = $fo; } public function getFo() { return $this->fo; } public function setBar($bar) { $this->bar = $bar; } public function getBar() { return $this->bar; } public function setUnused($unused) { $this->unused = $unused; } public function getUnused() { return $this->unused; } public static function getMapping() { return array( 'foo' => 'fo', 'bar' => 'bar', 'unused' => null ); } } ================================================ FILE: tests/Transmission/Tests/ClientTest.php ================================================ assertEquals('localhost', $this->getClient()->getHost()); } /** * @test */ public function shouldHaveDefaultPort() { $this->assertEquals(9091, $this->getClient()->getPort()); } /** * @test */ public function shouldHaveNoTokenOnInstantiation() { $this->assertEmpty($this->getClient()->getToken()); } /** * @test */ public function shouldHaveDefaultClient() { $this->assertInstanceOf('Buzz\Client\Curl', $this->getClient()->getClient()); } /** * @test */ public function shouldGenerateDefaultUrl() { $this->assertEquals('http://localhost:9091', $this->getClient()->getUrl()); } /** * @test */ public function shouldMakeApiCall() { $test = $this; $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->once()) ->method('send') ->with( $this->isInstanceOf('Buzz\Message\Request'), $this->isInstanceOf('Buzz\Message\Response') ) ->will($this->returnCallback(function ($request, $response) use ($test) { $test->assertEquals('POST', $request->getMethod()); $test->assertEquals('/transmission/rpc', $request->getResource()); $test->assertEquals('http://localhost:9091', $request->getHost()); $test->assertEmpty($request->getHeader('X-Transmission-Session-Id')); $test->assertEquals('{"method":"foo","arguments":{"bar":"baz"}}', $request->getContent()); $response->addHeader('HTTP/1.1 200 OK'); $response->addHeader('Content-Type: application/json'); $response->addHeader('X-Transmission-Session-Id: foo'); $response->setContent('{"foo":"bar"}'); })); $this->getClient()->setClient($client); $response = $this->getClient()->call('foo', array('bar' => 'baz')); $this->assertInstanceOf('stdClass', $response); $this->assertObjectHasAttribute('foo', $response); $this->assertEquals('bar', $response->foo); } /** * @test */ public function shouldAuthenticate() { $test = $this; $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->once()) ->method('send') ->with( $this->isInstanceOf('Buzz\Message\Request'), $this->isInstanceOf('Buzz\Message\Response') ) ->will($this->returnCallback(function ($request, $response) use ($test) { $test->assertEquals('POST', $request->getMethod()); $test->assertEquals('/transmission/rpc', $request->getResource()); $test->assertEquals('http://localhost:9091', $request->getHost()); $test->assertEmpty($request->getHeader('X-Transmission-Session-Id')); $test->assertEquals('Basic '. base64_encode('foo:bar'), $request->getHeader('Authorization')); $test->assertEquals('{"method":"foo","arguments":{"bar":"baz"}}', $request->getContent()); $response->addHeader('HTTP/1.1 200 OK'); $response->addHeader('Content-Type: application/json'); $response->addHeader('X-Transmission-Session-Id: foo'); $response->setContent('{"foo":"bar"}'); })); $this->getClient()->authenticate('foo', 'bar'); $this->getClient()->setClient($client); $response = $this->getClient()->call('foo', array('bar' => 'baz')); $this->assertInstanceOf('stdClass', $response); $this->assertObjectHasAttribute('foo', $response); $this->assertEquals('bar', $response->foo); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnExceptionDuringApiCall() { $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->once()) ->method('send') ->will($this->throwException(new \Exception())); $this->getClient()->setClient($client); $this->getClient()->call('foo', array()); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnUnexpectedStatusCode() { $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->once()) ->method('send') ->will($this->returnCallback(function ($request, $response) { $response->addHeader('HTTP/1.1 500 Internal Server Error'); })); $this->getClient()->setClient($client); $this->getClient()->call('foo', array()); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnAccessDenied() { $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->once()) ->method('send') ->will($this->returnCallback(function ($request, $response) { $response->addHeader('HTTP/1.1 401 Access Denied'); })); $this->getClient()->setClient($client); $this->getClient()->call('foo', array()); } /** * @test */ public function shouldHandle409ResponseWhenMakingAnApiCall() { $test = $this; $client = $this->getMock('Buzz\Client\Curl'); $client->expects($this->at(0)) ->method('send') ->will($this->returnCallback(function ($request, $response) use ($test) { $test->assertEmpty($request->getHeader('X-Transmission-Session-Id')); $response->addHeader('HTTP/1.1 409 Conflict'); $response->addHeader('X-Transmission-Session-Id: foo'); })); $client->expects($this->at(1)) ->method('send') ->will($this->returnCallback(function ($request, $response) { $response->addHeader('HTTP/1.1 200 OK'); $response->addHeader('Content-Type: application/json'); $response->addHeader('X-Transmission-Session-Id: foo'); $response->setContent('{"foo":"bar"}'); })); $this->getClient()->setClient($client); $response = $this->getClient()->call('foo', array()); $this->assertEquals('foo', $this->getClient()->getToken()); $this->assertInstanceOf('stdClass', $response); $this->assertObjectHasAttribute('foo', $response); $this->assertEquals('bar', $response->foo); } public function setup() { $this->client = new Client(); } private function getClient() { return $this->client; } } ================================================ FILE: tests/Transmission/Tests/Model/AbstractModelTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getModel()); } /** * @test */ public function shouldHaveEmptyMappingByDefault() { $this->assertEmpty($this->getModel()->getMapping()); } /** * @test */ public function shouldHaveNoClientByDefault() { $this->assertNull($this->getModel()->getClient()); } /** * @test */ public function shouldHaveClientIfSetByUser() { $client = $this->getMock('Transmission\Client'); $this->getModel()->setClient($client); $this->assertEquals($client, $this->getModel()->getClient()); } public function setup() { $this->model = $this->getMockForAbstractClass('Transmission\Model\AbstractModel'); } private function getModel() { return $this->model; } } ================================================ FILE: tests/Transmission/Tests/Model/FileTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getFile()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getFile()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'name' => 'foo', 'length' => 100, 'bytesCompleted' => 10 ); PropertyMapper::map($this->getFile(), $source); $this->assertEquals('foo', $this->getFile()->getName()); $this->assertEquals(100, $this->getFile()->getSize()); $this->assertEquals(10, $this->getFile()->getCompleted()); $this->assertFalse($this->getFile()->isDone()); } /** * @test */ public function shouldConvertToString() { $this->getFile()->setName('foo'); $this->assertInternalType('string', (string) $this->getFile()); $this->assertEquals('foo', (string) $this->getFile()); } public function setup() { $this->file = new File(); } private function getFile() { return $this->file; } } ================================================ FILE: tests/Transmission/Tests/Model/PeerTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getPeer()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getPeer()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'address' => 'foo', 'clientName' => 'foo', 'clientIsChoked' => false, 'clientIsInterested' => true, 'flagStr' => 'foo', 'isDownloadingFrom' => false, 'isEncrypted' => true, 'isIncoming' => false, 'isUploadingTo' => true, 'isUTP' => false, 'peerIsChoked' => true, 'peerIsInterested' => false, 'port' => 3000, 'progress' => 10.5, 'rateToClient' => 1000, 'rateFromClient' => 10000 ); PropertyMapper::map($this->getPeer(), $source); $this->assertEquals('foo', $this->getPeer()->getAddress()); $this->assertEquals('foo', $this->getPeer()->getClientName()); $this->assertFalse($this->getPeer()->isClientChoked()); $this->assertTrue($this->getPeer()->isClientInterested()); $this->assertFalse($this->getPeer()->isDownloading()); $this->assertTrue($this->getPeer()->isEncrypted()); $this->assertFalse($this->getPeer()->isIncoming()); $this->assertTrue($this->getPeer()->isUploading()); $this->assertFalse($this->getPeer()->isUtp()); $this->assertTrue($this->getPeer()->isPeerChoked()); $this->assertFalse($this->getPeer()->isPeerInterested()); $this->assertEquals(3000, $this->getPeer()->getPort()); $this->assertEquals(10.5, $this->getPeer()->getProgress()); $this->assertEquals(1000, $this->getPeer()->getUploadRate()); $this->assertEquals(10000, $this->getPeer()->getDownloadRate()); } public function setup() { $this->peer = new Peer(); } public function getPeer() { return $this->peer; } } ================================================ FILE: tests/Transmission/Tests/Model/SessionTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getSession()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getSession()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'alt-speed-down' => 1, 'alt-speed-enabled' => true, 'download-dir' => 'foo', 'download-queue-enabled' => true, 'download-queue-size' => 5, 'incomplete-dir' => 'bar', 'incomplete-dir-enabled' => true, 'script-torrent-done-filename' => 'baz', 'script-torrent-done-enabled' => true, 'seedRatioLimit' => 3.14, 'seedRatioLimited' => true, 'seed-queue-size' => 5, 'seed-queue-enabled' => true, 'speed-limit-down' => 100, 'speed-limit-down-enabled' => true, 'speed-limit-up' => 100, 'speed-limit-up-enabled' => true ); PropertyMapper::map($this->getSession(), $source); $this->assertEquals(1, $this->getSession()->getAltSpeedDown()); $this->assertTrue($this->getSession()->isAltSpeedEnabled()); $this->assertEquals('foo', $this->getSession()->getDownloadDir()); $this->assertEquals(5, $this->getSession()->getDownloadQueueSize()); $this->assertTrue($this->getSession()->isDownloadQueueEnabled()); $this->assertEquals('bar', $this->getSession()->getIncompleteDir()); $this->assertTrue($this->getSession()->isIncompleteDirEnabled()); $this->assertEquals('baz', $this->getSession()->getTorrentDoneScript()); $this->assertTrue($this->getSession()->isTorrentDoneScriptEnabled()); $this->assertEquals(3.14, $this->getSession()->getSeedRatioLimit()); $this->assertTrue($this->getSession()->isSeedRatioLimited()); $this->assertEquals(5, $this->getSession()->getSeedQueueSize()); $this->assertTrue($this->getSession()->isSeedQueueEnabled()); $this->assertEquals(100, $this->getSession()->getDownloadSpeedLimit()); $this->assertTrue($this->getSession()->isDownloadSpeedLimitEnabled()); $this->assertEquals(100, $this->getSession()->getUploadSpeedLimit()); $this->assertTrue($this->getSession()->isUploadSpeedLimitEnabled()); } /** * @test */ public function shouldSave() { $expected = array( 'alt-speed-down' => 1, 'alt-speed-enabled' => true, 'download-dir' => 'foo', 'download-queue-enabled' => true, 'download-queue-size' => 5, 'incomplete-dir' => 'bar', 'incomplete-dir-enabled' => true, 'script-torrent-done-filename' => 'baz', 'script-torrent-done-enabled' => true, 'seedRatioLimit' => 3.14, 'seedRatioLimited' => true, 'seed-queue-size' => 5, 'seed-queue-enabled' => true, 'speed-limit-down' => 100, 'speed-limit-down-enabled' => true, 'speed-limit-up' => 100, 'speed-limit-up-enabled' => true ); PropertyMapper::map($this->getSession(), (object) $expected); $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('session-set', $expected) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success', ); })); $this->getSession()->setClient($client); $this->getSession()->save(); } /** * @test */ public function shouldNotSaveWithNoClient() { $this->getSession()->save(); } public function setup() { $this->session = new Session(); } protected function getSession() { return $this->session; } } ================================================ FILE: tests/Transmission/Tests/Model/StatusTest.php ================================================ assertTrue($status->isStopped()); } } ================================================ FILE: tests/Transmission/Tests/Model/TorrentTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getTorrent()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getTorrent()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'id' => 1, 'eta' => 10, 'sizeWhenDone' => 10000, 'name' => 'foo', 'hashString' => 'bar', 'status' => 0, 'isFinished' => false, 'rateUpload' => 10, 'rateDownload' => 100, 'downloadDir' => '/home/foo', 'downloadedEver' => 1024000000, 'uploadedEver' => 1024000000000, // 1 Tb 'files' => array( (object) array() ), 'peers' => array( (object) array(), (object) array() ), 'peersConnected' => 10, 'startDate' => 1427583510, 'trackers' => array( (object) array(), (object) array(), (object) array() ), 'trackerStats' => array( (object) array(), (object) array(), (object) array() ) ); PropertyMapper::map($this->getTorrent(), $source); $this->assertEquals(1, $this->getTorrent()->getId()); $this->assertEquals(10, $this->getTorrent()->getEta()); $this->assertEquals(10000, $this->getTorrent()->getSize()); $this->assertEquals('foo', $this->getTorrent()->getName()); $this->assertEquals('bar', $this->getTorrent()->getHash()); $this->assertEquals(0, $this->getTorrent()->getStatus()); $this->assertFalse($this->getTorrent()->isFinished()); $this->assertEquals(10, $this->getTorrent()->getUploadRate()); $this->assertEquals(100, $this->getTorrent()->getDownloadRate()); $this->assertEquals('/home/foo', $this->getTorrent()->getDownloadDir()); $this->assertEquals(1024000000, $this->getTorrent()->getDownloadedEver()); $this->assertEquals(1024000000000, $this->getTorrent()->getUploadedEver()); $this->assertCount(1, $this->getTorrent()->getFiles()); $this->assertCount(2, $this->getTorrent()->getPeers()); $this->assertCount(3, $this->getTorrent()->getTrackers()); } /** * @test */ public function shouldBeDoneWhenFinishedFlagIsSet() { $this->getTorrent()->setFinished(true); $this->assertTrue($this->getTorrent()->isFinished()); } /** * @test */ public function shouldBeDoneWhenPercentDoneIs100Percent() { $this->getTorrent()->setPercentDone(1); $this->assertTrue($this->getTorrent()->isFinished()); } /** * @test * @dataProvider statusProvider */ public function shouldHaveConvenienceMethods($status, $method) { $methods = array('stopped', 'checking', 'downloading', 'seeding'); $accessor = PropertyAccess::createPropertyAccessor(); $this->getTorrent()->setStatus($status); $methods = array_filter($methods, function ($value) use ($method) { return $method !== $value; }); $this->assertTrue($accessor->getValue($this->getTorrent(), $method)); foreach ($methods as $m) { $this->assertFalse($accessor->getValue($this->getTorrent(), $m), $m); } } public function statusProvider() { return array( array(0, 'stopped'), array(1, 'checking'), array(2, 'checking'), array(3, 'downloading'), array(4, 'downloading'), array(5, 'seeding'), array(6, 'seeding') ); } public function setup() { $this->torrent = new Torrent(); } public function getTorrent() { return $this->torrent; } } ================================================ FILE: tests/Transmission/Tests/Model/TrackerStatsTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getTrackerStats()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getTrackerStats()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'host' => 'test', 'leecherCount' => 1, 'seederCount' => 2, 'lastScrapeResult' => 'foo', 'lastAnnounceResult' => 'bar' ); PropertyMapper::map($this->getTrackerStats(), $source); $this->assertEquals('test', $this->getTrackerStats()->getHost()); $this->assertEquals(1, $this->getTrackerStats()->getLeecherCount()); $this->assertEquals(2, $this->getTrackerStats()->getSeederCount()); $this->assertEquals('foo', $this->getTrackerStats()->getLastScrapeResult()); $this->assertEquals('bar', $this->getTrackerStats()->getLastAnnounceResult()); } public function setup() { $this->trackerStats = new TrackerStats(); } private function getTrackerStats() { return $this->trackerStats; } } ================================================ FILE: tests/Transmission/Tests/Model/TrackerTest.php ================================================ assertInstanceOf('Transmission\Model\ModelInterface', $this->getTracker()); } /** * @test */ public function shouldHaveNonEmptyMapping() { $this->assertNotEmpty($this->getTracker()->getMapping()); } /** * @test */ public function shouldBeCreatedFromMapping() { $source = (object) array( 'id' => 1, 'tier' => 1, 'scrape' => 'foo', 'announce' => 'bar' ); PropertyMapper::map($this->getTracker(), $source); $this->assertEquals(1, $this->getTracker()->getId()); $this->assertEquals(1, $this->getTracker()->getTier()); $this->assertEquals('foo', $this->getTracker()->getScrape()); $this->assertEquals('bar', $this->getTracker()->getAnnounce()); } public function setup() { $this->tracker = new Tracker(); } private function getTracker() { return $this->tracker; } } ================================================ FILE: tests/Transmission/Tests/TransmissionTest.php ================================================ assertEquals('localhost', $this->getTransmission()->getClient()->getHost()); } /** * @test */ public function shouldGetAllTorrentsInDownloadQueue() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-get') ->will($this->returnCallback(function ($method, $arguments) { return (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrents' => array( (object) array(), (object) array(), (object) array(), ) ) ); })); $this->getTransmission()->setClient($client); $torrents = $this->getTransmission()->all(); $this->assertCount(3, $torrents); } /** * @test */ public function shouldGetTorrentById() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-get') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertEquals(1, $arguments['ids'][0]); return (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrents' => array( (object) array() ) ) ); })); $this->getTransmission()->setClient($client); $torrent = $this->getTransmission()->get(1); $this->assertInstanceOf('Transmission\Model\Torrent', $torrent); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionWhenTorrentIsNotFound() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-get') ->will($this->returnCallback(function ($method, $arguments) { return (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrents' => array() ) ); })); $this->getTransmission()->setClient($client); $this->getTransmission()->get(1); } /** * @test */ public function shouldAddTorrentByFilename() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-add') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertArrayHasKey('filename', $arguments); return (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrent-added' => (object) array() ) ); })); $this->getTransmission()->setClient($client); $torrent = $this->getTransmission()->add('foo'); $this->assertInstanceOf('Transmission\Model\Torrent', $torrent); } /** * @test */ public function shouldAddTorrentByMetainfo() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-add') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertArrayHasKey('metainfo', $arguments); return (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrent-added' => (object) array() ) ); })); $this->getTransmission()->setClient($client); $torrent = $this->getTransmission()->add('foo', true); $this->assertInstanceOf('Transmission\Model\Torrent', $torrent); } /** * @test */ public function shouldHandleDuplicateTorrent() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-add') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertArrayHasKey('metainfo', $arguments); return (object) array( 'result' => 'duplicate torrent', 'arguments' => (object) array( 'torrent-duplicate' => (object) array() ) ); })); $this->getTransmission()->setClient($client); $torrent = $this->getTransmission()->add('foo', true); $this->assertInstanceOf('Transmission\Model\Torrent', $torrent); } /** * @test */ public function shouldGetSession() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('session-get') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertEmpty($arguments); return (object) array( 'result' => 'success', 'arguments' => (object) array() ); })); $this->getTransmission()->setClient($client); $session = $this->getTransmission()->getSession(); $this->assertInstanceOf('Transmission\Model\Session', $session); } /** * @test */ public function shouldGetSessionStats() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('session-stats') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertEmpty($arguments); return (object) array( 'result' => 'success', 'arguments' => (object) array() ); })); $this->getTransmission()->setClient($client); $stats = $this->getTransmission()->getSessionStats(); $this->assertInstanceOf('Transmission\Model\Stats\Session', $stats); } /** * @test */ public function shouldGetFreeSpace() { $that = $this; $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('free-space') ->will($this->returnCallback(function ($method, $arguments) use ($that) { $that->assertArrayHasKey('path', $arguments); return (object) array( 'result' => 'success', 'arguments' => (object) array() ); })); $this->getTransmission()->setClient($client); $freeSpace = $this->getTransmission()->getFreeSpace('/'); $this->assertInstanceOf('Transmission\Model\FreeSpace', $freeSpace); } /** * @test */ public function shouldStartDownload() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-start', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->start($torrent); } /** * @test */ public function shouldStartDownloadImmediately() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-start-now', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->start($torrent, true); } /** * @test */ public function shouldStopDownload() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-stop', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->stop($torrent); } /** * @test */ public function shouldVerifyDownload() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-verify', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->verify($torrent); } /** * @test */ public function shouldReannounceDownload() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-reannounce', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->reannounce($torrent); } /** * @test */ public function shouldRemoveDownloadWithoutRemovingLocalData() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-remove', array('ids' => array(1))) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->remove($torrent); } /** * @test */ public function shouldRemoveDownloadWithRemovingLocalData() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('call') ->with('torrent-remove', array('ids' => array(1), 'delete-local-data' => true)) ->will($this->returnCallback(function () { return (object) array( 'result' => 'success' ); })); $torrent = new Torrent(); $torrent->setId(1); $transmission = new Transmission(); $transmission->setClient($client); $transmission->remove($torrent, true); } /** * @test */ public function shouldHaveDefaultPort() { $this->assertEquals(9091, $this->getTransmission()->getClient()->getPort()); } /** * @test */ public function shouldProvideFacadeForClient() { $client = $this->getMock('Transmission\Client'); $client->expects($this->once()) ->method('setHost') ->with('example.org'); $client->expects($this->once()) ->method('getHost') ->will($this->returnValue('example.org')); $client->expects($this->once()) ->method('setPort') ->with(80); $client->expects($this->once()) ->method('getPort') ->will($this->returnValue(80)); $this->getTransmission()->setClient($client); $this->getTransmission()->setHost('example.org'); $this->getTransmission()->setPort(80); $this->assertEquals('example.org', $this->getTransmission()->getHost()); $this->assertEquals(80, $this->getTransmission()->getPort()); } public function setup() { $this->transmission = new Transmission(); } private function getTransmission() { return $this->transmission; } } ================================================ FILE: tests/Transmission/Tests/Util/PropertyMapperTest.php ================================================ 'this', 'bar' => 'that', 'ba' => 'thus', 'unused' => false ); $model = new \Transmission\Mock\Model(); $this->getMapper()->map($model, $source); $this->assertEquals('this', $model->getFo()); $this->assertEquals('that', $model->getBar()); $this->assertNull($model->getUnused()); } public function setup() { $this->mapper = new PropertyMapper(); } private function getMapper() { return $this->mapper; } } ================================================ FILE: tests/Transmission/Tests/Util/ResponseValidatorTest.php ================================================ getValidator()->validate('', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnErrorResultField() { $response = (object) array('result' => 'error'); $this->getValidator()->validate('', $response); } /** * @test */ public function shouldThrowNoExceptionOnValidTorrentGetResponse() { $response = (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrents' => array( (object) array('foo' => 'bar') ) ) ); $expected = array((object) array('foo' => 'bar')); $container = $this->getValidator()->validate('torrent-get', $response); $this->assertEquals($expected, $container); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingArgumentsInTorrentGetResponse() { $response = (object) array('result' => 'success'); $this->getValidator()->validate('torrent-get', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingTorrentArgumentInTorrentGetResponse() { $response = (object) array('result' => 'success', 'arguments' => (object) array()); $this->getValidator()->validate('torrent-get', $response); } /** * @test */ public function shouldThrowNoExceptionOnValidTorrentAddResponse() { $response = (object) array( 'result' => 'success', 'arguments' => (object) array( 'torrent-added' => (object) array( 'foo' => 'bar' ) ) ); $expected = (object) array('foo' => 'bar'); $container = $this->getValidator()->validate('torrent-add', $response); $this->assertEquals($expected, $container); } /** * @test */ public function shouldThrowNoExceptionOnValidSessionGetResponse() { $response = (object) array( 'result' => 'success', 'arguments' => (object) array( 'foo' => 'bar' ) ); $expected = (object) array('foo' => 'bar'); $container = $this->getValidator()->validate('session-get', $response); $this->assertEquals($expected, $container); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingArgumentsInSessionGetResponse() { $response = (object) array('result' => 'success'); $this->getValidator()->validate('session-get', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingArgumentsSessionGetResponse() { $response = (object) array('result' => 'success'); $this->getValidator()->validate('session-get', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingArgumentsInTorrentAddResponse() { $response = (object) array('result' => 'success'); $this->getValidator()->validate('torrent-add', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnMissingTorrentFieldArgumentInTorrentAddResponse() { $response = (object) array('result' => 'success', 'arguments' => (object) array()); $this->getValidator()->validate('torrent-add', $response); } /** * @test * @expectedException RuntimeException */ public function shouldThrowExceptionOnEmptyTorrentFieldInTorrentAddResponse() { $response = (object) array('result' => 'success', 'arguments' => (object) array('torrent-added' => array())); $this->getValidator()->validate('torrent-add', $response); } /** * @test */ public function shouldThrowNoExceptionOnValidOtherResponses() { $response = (object) array('result' => 'success'); $container = $this->getValidator()->validate('torrent-remove', $response); $this->assertNull($container); } public function setup() { $this->validator = new ResponseValidator(); } private function getValidator() { return $this->validator; } } ================================================ FILE: tests/bootstrap.php ================================================ add('Transmission\Mock', __DIR__); $loader->add('Transmission\Tests', __DIR__);