diff --git a/.tests/fixtures/fixture_admin.xml b/.tests/fixtures/fixture_admin.xml
new file mode 100644
index 0000000..a8319bb
--- /dev/null
+++ b/.tests/fixtures/fixture_admin.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+ 1
+ admin
+ $2y$10$7OvZrKgonVZM9lkzrTbiou.CVhO3HjPk5y0W9L68fVwPs/osBRIMq
+
+
+
+
diff --git a/.tests/fixtures/fixture_empty.xml b/.tests/fixtures/fixture_empty.xml
new file mode 100644
index 0000000..51c44ba
--- /dev/null
+++ b/.tests/fixtures/fixture_empty.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.tests/lib/BaseDatabaseTestCase.php b/.tests/lib/BaseDatabaseTestCase.php
new file mode 100644
index 0000000..6740020
--- /dev/null
+++ b/.tests/lib/BaseDatabaseTestCase.php
@@ -0,0 +1,171 @@
+load();
+ $dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS']);
+ }
+
+ $db_host = getenv('DB_HOST');
+ $db_name = getenv('DB_NAME');
+ $db_user = getenv('DB_USER');
+ $db_pass = getenv('DB_PASS');
+ $db_port = getenv('DB_PORT') ?: NULL;
+ $db_dsn = "mysql:dbname={$db_name};host={$db_host}";
+ if (!empty($db_port)) {
+ $db_dsn .= ";port={$db_port}";
+ }
+
+ // pdo connection
+ if (self::$pdo == null) {
+ self::$pdo = new PDO($db_dsn, $db_user, $db_pass);;
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ self::$pdo = null;
+ }
+
+ /**
+ * Set up database connection
+ * This will also override uDb class connection
+ *
+ * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
+ */
+ public function getConnection() {
+ if ($this->conn === null) {
+ $this->conn = $this->createDefaultDBConnection(self::$pdo, getenv('DB_NAME'));
+ }
+ return $this->conn;
+ }
+
+ /**
+ * Create data set from xml fixture
+ *
+ * @return PHPUnit_Extensions_Database_DataSet_IDataSet
+ */
+ protected function getDataSet() {
+ return $this->createMySQLXMLDataSet(__DIR__ . '/../fixtures/fixture_empty.xml');
+ }
+
+ /**
+ * Insert to database from array
+ *
+ * @param string $table Table name
+ * @param array $rowsArr Array of rows
+ * @return int|null Last insert id if available, NULL otherwise
+ */
+ private function pdoInsert($table, $rowsArr = []) {
+ $ret = NULL;
+ if (!empty($rowsArr)) {
+ $values = ':' . implode(', :', array_keys($rowsArr));
+ $columns = implode(', ', array_keys($rowsArr));
+ $query = "INSERT INTO $table ($columns) VALUES ($values)";
+ $stmt = self::$pdo->prepare($query);
+ if ($stmt !== false) {
+ $stmt->execute(array_combine(explode(', ', $values), array_values($rowsArr)));
+ }
+ $ret = self::$pdo->lastInsertId();
+ }
+ return $ret;
+ }
+
+ /**
+ * Get single column from first row of query result
+ *
+ * @param string $query SQL query
+ * @param int $columnNumber Optional column number (default is first column)
+ * @return string|bool Column or false if no data
+ */
+ protected function pdoGetColumn($query, $columnNumber = 0) {
+ $column = false;
+ $stmt = self::$pdo->query($query);
+ if ($stmt !== false) {
+ $column = $stmt->fetchColumn($columnNumber);
+ $stmt->closeCursor();
+ }
+ return $column;
+ }
+
+ /**
+ * Insert user data to database
+ * If parameters are omitted they default test values are used
+ *
+ * @param string $user User login
+ * @param string $pass User password
+ * @return int|bool User id or false on error
+ */
+ protected function addTestUser($user = NULL, $pass = NULL) {
+ if (is_null($user)) { $user = $this->testUser; }
+ if (is_null($pass)) { $pass = $this->testPass; }
+ return $this->pdoInsert('users', [ 'login' => $user, 'password' => $pass ]);
+ }
+
+ /**
+ * Insert track data to database.
+ * If parameters are omitted they default test values are used
+ *
+ * @param int $userId Optional track id
+ * @param string $trackName Optional track name
+ * @param string $comment Optional comment
+ * @return int|bool Track id or false on error
+ */
+ protected function addTestTrack($userId = NULL, $trackName = NULL, $comment = NULL) {
+ if (is_null($userId)) { $userId = $this->testUserId; }
+ if (is_null($trackName)) { $trackName = $this->testTrackName; }
+ if (is_null($comment)) { $comment = $this->testComment; }
+ return $this->pdoInsert('tracks', [ 'user_id' => $userId, 'name' => $trackName, 'comment' => $comment ]);
+ }
+
+ /**
+ * Insert position data to database
+ * If parameters are omitted they default test values are used
+ *
+ * @param int $userId
+ * @param int $trackId
+ * @param int $timeStamp
+ * @param double $latitude
+ * @param double $longitude
+ * @return int|bool Position id or false on error
+ */
+ protected function addTestPosition($userId = NULL, $trackId = NULL, $timeStamp = NULL, $latitude = NULL, $longitude = NULL) {
+ if (is_null($userId)) { $userId = $this->testUserId; }
+ if (is_null($trackId)) { $trackId = $this->testTrackId; }
+ if (is_null($timeStamp)) { $timeStamp = $this->testTimestamp; }
+ if (is_null($latitude)) { $latitude = $this->testLat; }
+ if (is_null($longitude)) { $longitude = $this->testLon; }
+
+ return $this->pdoInsert('positions', [ "user_id" => $userId, "track_id" => $trackId, "time" => date("Y-m-d H:m:s", $timeStamp), "latitude" => $latitude, "longitude" => $longitude ]);
+ }
+}
+?>
diff --git a/.tests/lib/UloggerAPITestCase.php b/.tests/lib/UloggerAPITestCase.php
new file mode 100644
index 0000000..bdc0336
--- /dev/null
+++ b/.tests/lib/UloggerAPITestCase.php
@@ -0,0 +1,52 @@
+load();
+ $dotenv->required(['ULOGGER_URL']);
+ }
+
+ $url = getenv('ULOGGER_URL');
+
+ $this->http = new GuzzleHttp\Client([ 'base_uri' => $url, 'cookies' => true ]);
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+ $this->http = null;
+ }
+
+ protected function getDataSet() {
+ return $this->createMySQLXMLDataSet(__DIR__ . '/../fixtures/fixture_admin.xml');
+ }
+
+ /**
+ * Authenticate on server
+ * @param string $user Login
+ *
+ * @return bool true on success, false otherwise
+ */
+ public function authenticate($user = NULL, $pass = NULL) {
+
+ if (is_null($user)) { $user = $this->testAdminUser; }
+ if (is_null($pass)) { $pass = $this->testAdminPass; }
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'auth', 'user' => $user, 'pass' => $pass ],
+ ];
+
+ $response = $this->http->post('/client/index.php', $options);
+ return ($response->getStatusCode() == 200);
+ }
+}
+?>
diff --git a/.tests/lib/UloggerDatabaseTestCase.php b/.tests/lib/UloggerDatabaseTestCase.php
new file mode 100644
index 0000000..ae114db
--- /dev/null
+++ b/.tests/lib/UloggerDatabaseTestCase.php
@@ -0,0 +1,40 @@
+load();
+ $dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS']);
+ }
+
+ $db_host = getenv('DB_HOST');
+ $db_name = getenv('DB_NAME');
+ $db_user = getenv('DB_USER');
+ $db_pass = getenv('DB_PASS');
+ $db_port = getenv('DB_PORT') ?: NULL;
+
+ // uDb connection
+ if (self::$udb == null) {
+ self::$udb = new ReflectionClass("uDb");
+ $dbInstance = self::$udb->getProperty('instance');
+ $dbInstance->setAccessible(true);
+ $dbInstance->setValue(new uDb($db_host, $db_user, $db_pass, $db_name, $db_port));
+ }
+ }
+
+ public static function tearDownAfterClass() {
+ parent::tearDownAfterClass();
+ self::$udb = null;
+ }
+}
+?>
diff --git a/.tests/phpunit.xml b/.tests/phpunit.xml
new file mode 100644
index 0000000..acdbf15
--- /dev/null
+++ b/.tests/phpunit.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ tests
+
+
+
+
+ ..
+
+ ../.tests
+ ../vendor
+
+
+
+
+
+
+
diff --git a/.tests/tests/AuthTest.php b/.tests/tests/AuthTest.php
new file mode 100644
index 0000000..9b56d8d
--- /dev/null
+++ b/.tests/tests/AuthTest.php
@@ -0,0 +1,158 @@
+addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $_REQUEST = $this->request($this->testUser, $this->testPass);
+
+ $auth = new uAuth();
+ $this->assertTrue($auth->isAuthenticated(), "Not authenticated");
+ $this->assertTrue($auth->isLoginAttempt(), "Not login attempt");
+ $this->assertTrue($auth->user instanceof uUser, "User variable not set");
+ $this->assertEquals($this->testUser, $auth->user->login, "Wrong login");
+ $this->assertEquals($_SESSION["user"]->login, $auth->user->login, "Wrong login");
+ $this->assertTrue($_SESSION["user"] instanceof uUser, "User not set in session");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testLoginBadPass() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $_REQUEST = $this->request($this->testUser, "badPass");
+
+ $auth = new uAuth();
+ $this->assertFalse($auth->isAuthenticated(), "Should not be authenticated");
+ $this->assertTrue($auth->isLoginAttempt(), "Not login attempt");
+ $this->assertTrue(is_null($auth->user), "User not null");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testLoginEmptyLogin() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $_REQUEST = $this->request("", $this->testPass);
+
+ $auth = new uAuth();
+ $this->assertFalse($auth->isAuthenticated(), "Should not be authenticated");
+ $this->assertTrue($auth->isLoginAttempt(), "Not login attempt");
+ $this->assertTrue(is_null($auth->user), "User not null");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testLoginNoFormData() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $auth = new uAuth();
+ $this->assertFalse($auth->isAuthenticated(), "Should not be authenticated");
+ $this->assertFalse($auth->isLoginAttempt(), "Should not be login attempt");
+ $this->assertTrue(is_null($auth->user), "User not null");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testSessionAuth() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $user = new uUser($this->testUser);
+ $this->assertTrue($user->isValid, "User not valid");
+ session_name("ulogger");
+ session_start();
+ $_SESSION["user"] = $user;
+ unset($user);
+
+ @$auth = new uAuth();
+ $this->assertTrue($auth->isAuthenticated(), "Should be authenticated");
+ $this->assertFalse($auth->isLoginAttempt(), "Should not be login attempt");
+ $this->assertEquals($this->testUser, $auth->user->login, "Wrong login");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testSessionAndRequest() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $_REQUEST = $this->request($this->testUser, $this->testPass);
+
+ $user = new uUser($this->testUser);
+ $this->assertTrue($user->isValid, "User not valid");
+ session_name("ulogger");
+ session_start();
+ $_SESSION["user"] = $user;
+ unset($user);
+
+ @$auth = new uAuth();
+ $this->assertTrue($auth->isAuthenticated(), "Should be authenticated");
+ $this->assertFalse($auth->isLoginAttempt(), "Should not be login attempt");
+ $this->assertEquals($this->testUser, $auth->user->login, "Wrong login");
+ }
+
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testNotIsAdmin() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $_REQUEST = $this->request($this->testUser, $this->testPass);
+
+ @$auth = new uAuth();
+ $this->assertTrue($auth->isAuthenticated(), "Should be authenticated");
+ $this->assertFalse($auth->isAdmin(), "Should not be admin");
+ }
+
+ /**
+ * @runInSeparateProcess
+ */
+ public function testIsAdmin() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ uConfig::$admin_user = $this->testUser;
+ $_REQUEST = $this->request($this->testUser, $this->testPass);
+
+ @$auth = new uAuth();
+ $this->assertTrue($auth->isAuthenticated(), "Should be authenticated");
+ $this->assertTrue($auth->isAdmin(), "Should not be admin");
+ }
+
+}
+?>
diff --git a/.tests/tests/ClientAPITest.php b/.tests/tests/ClientAPITest.php
new file mode 100644
index 0000000..0ccd670
--- /dev/null
+++ b/.tests/tests/ClientAPITest.php
@@ -0,0 +1,379 @@
+assertTrue($this->authenticate(), "Authentication failed");
+ $options = [
+ 'http_errors' => false
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ }
+
+ /* auth */
+
+ public function testAuthOk() {
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'auth', 'user' => $this->testAdminUser, 'pass' => $this->testAdminPass ],
+ ];
+
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertFalse($json->{'error'}, "Unexpected error");
+ }
+
+ public function testAuthFail() {
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'user' => 'noexist', 'pass' => 'noexist' ],
+ ];
+
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(401, $response->getStatusCode(), "Unexpected status code");
+ }
+
+ /* adduser */
+
+ public function testAddUser() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'login' => $this->testUser, 'password' => $this->testPass ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertFalse($json->{'error'}, "Unexpected error");
+ $this->assertEquals(2, $json->{'userid'}, "Wrong user id");
+ $this->assertEquals(2, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ $expected = [ "id" => 2, "login" => $this->testUser ];
+ $actual = $this->getConnection()->createQueryTable("users", "SELECT id, login FROM users");
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+ }
+
+ public function testAddUserExistingLogin() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'login' => $this->testAdminUser, 'password' => $this->testPass ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'userid'}), "Unexpected user id");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ }
+
+ public function testAddUserEmptyLogin() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'login' => '', 'password' => $this->testPass ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'userid'}), "Unexpected user id");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ }
+
+ public function testAddUserEmptyPass() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'login' => $this->testUser, 'password' => '' ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'userid'}), "Unexpected user id");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ }
+
+ public function testAddUserNoParameters() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser' ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'userid'}), "Unexpected user id");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ }
+
+ public function testAddUserByNonAdmin() {
+ $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT));
+ $this->assertTrue($this->authenticate($this->testUser, $this->testPass), "Authentication failed");
+
+ $this->assertEquals(2, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'adduser', 'login' => $this->testUser2, 'password' => $this->testPass ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'userid'}), "Unexpected user id");
+ $this->assertEquals(2, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ }
+
+ /* addtrack */
+
+ public function testAddTrack() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'addtrack', 'track' => $this->testTrackName ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertFalse($json->{'error'}, "Unexpected error");
+ $this->assertEquals(1, $json->{'trackid'}, "Wrong track id");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $expected = [ "id" => 1, "user_id" => 1, "name" => $this->testTrackName ];
+ $actual = $this->getConnection()->createQueryTable("users", "SELECT id, user_id, name FROM tracks");
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+ }
+
+ public function testAddTrackEmptyName() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'addtrack', 'track' => '' ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'trackid'}), "Unexpected track id");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ }
+
+ public function testAddTrackNoParameters() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [ 'action' => 'addtrack' ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertFalse(isset($json->{'trackid'}), "Unexpected track id");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ }
+
+ /* addpos */
+
+ public function testAddPosition() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [
+ 'action' => 'addpos',
+ 'trackid' => $trackId,
+ 'time' => $this->testTimestamp,
+ 'lat' => $this->testLat,
+ 'lon' => $this->testLon,
+ 'altitude' => $this->testAltitude,
+ 'speed' => $this->testSpeed,
+ 'bearing' => $this->testBearing,
+ 'accuracy' => $this->testAccuracy,
+ 'provider' => $this->testProvider,
+ 'comment' => $this->testComment,
+ 'imageid' => $this->testImageId
+ ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertFalse($json->{'error'}, "Unexpected error");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $expected = [
+ "id" => 1,
+ "user_id" => $this->testUserId,
+ "track_id" => $trackId,
+ "time" => $this->testTimestamp,
+ "latitude" => $this->testLat,
+ "longitude" => $this->testLon,
+ "altitude" => $this->testAltitude,
+ "speed" => $this->testSpeed,
+ "bearing" => $this->testBearing,
+ "accuracy" => $this->testAccuracy,
+ "provider" => $this->testProvider,
+ "comment" => $this->testComment,
+ "image_id" => $this->testImageId
+ ];
+ $actual = $this->getConnection()->createQueryTable(
+ "positions",
+ "SELECT id, user_id, track_id, UNIX_TIMESTAMP(time) AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
+ );
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+ }
+
+ public function testAddPositionNoexistantTrack() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [
+ 'action' => 'addpos',
+ 'trackid' => $this->testTrackId,
+ 'time' => $this->testTimestamp,
+ 'lat' => $this->testLat,
+ 'lon' => $this->testLon,
+ 'altitude' => $this->testAltitude,
+ 'speed' => $this->testSpeed,
+ 'bearing' => $this->testBearing,
+ 'accuracy' => $this->testAccuracy,
+ 'provider' => $this->testProvider,
+ 'comment' => $this->testComment,
+ 'imageid' => $this->testImageId
+ ],
+ ];
+ $response = $this->http->post('/client/index.php', $options);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ }
+
+ public function testAddPositionEmptyParameters() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [
+ 'action' => 'addpos',
+ 'trackid' => $trackId,
+ 'time' => $this->testTimestamp,
+ 'lat' => $this->testLat,
+ 'lon' => $this->testLon,
+ 'altitude' => $this->testAltitude,
+ 'speed' => $this->testSpeed,
+ 'bearing' => $this->testBearing,
+ 'accuracy' => $this->testAccuracy,
+ 'provider' => $this->testProvider,
+ 'comment' => $this->testComment,
+ 'imageid' => $this->testImageId
+ ],
+ ];
+
+ // required
+ foreach ([ 'trackid', 'time', 'lat', 'lon' ] as $parameter) {
+ $optCopy = $options;
+ $optCopy['form_params'][$parameter] = '';
+ $response = $this->http->post('/client/index.php', $optCopy);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success ($parameter)");
+ }
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ }
+
+ public function testAddPositionMissingParameters() {
+ $this->assertTrue($this->authenticate(), "Authentication failed");
+
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $options = [
+ 'http_errors' => false,
+ 'form_params' => [
+ 'action' => 'addpos',
+ 'trackid' => $trackId,
+ 'time' => $this->testTimestamp,
+ 'lat' => $this->testLat,
+ 'lon' => $this->testLon,
+ 'altitude' => $this->testAltitude,
+ 'speed' => $this->testSpeed,
+ 'bearing' => $this->testBearing,
+ 'accuracy' => $this->testAccuracy,
+ 'provider' => $this->testProvider,
+ 'comment' => $this->testComment,
+ 'imageid' => $this->testImageId
+ ],
+ ];
+
+ // required
+ foreach ([ 'trackid', 'time', 'lat', 'lon' ] as $parameter) {
+ $optCopy = $options;
+ unset($optCopy['form_params'][$parameter]);
+ $response = $this->http->post('/client/index.php', $optCopy);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertTrue($json->{'error'}, "Unexpected success ($parameter)");
+ }
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ // optional
+ $optional = [ 'altitude', 'speed', 'bearing', 'accuracy', 'provider', 'comment', 'imageid' ];
+ foreach ($optional as $parameter) {
+ $optCopy = $options;
+ unset($optCopy['form_params'][$parameter]);
+ $response = $this->http->post('/client/index.php', $optCopy);
+ $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code");
+ $json = json_decode((string) $response->getBody());
+ $this->assertFalse($json->{'error'}, "Unexpected error ($parameter)");
+ }
+ $this->assertEquals(count($optional), $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ }
+
+
+}
+
+?>
diff --git a/.tests/tests/ConfigTest.php b/.tests/tests/ConfigTest.php
new file mode 100644
index 0000000..806cde7
--- /dev/null
+++ b/.tests/tests/ConfigTest.php
@@ -0,0 +1,62 @@
+assertRegExp($regex, $password0, "Regex: \"$regex\", password: \"$password0\"");
+ $this->assertRegExp($regex, $password1, "Regex: \"$regex\", password: \"$password1\"");
+ $this->assertRegExp($regex, $password2, "Regex: \"$regex\", password: \"$password2\"");
+ $this->assertRegExp($regex, $password3, "Regex: \"$regex\", password: \"$password3\"");
+
+ uConfig::$pass_strength = 1;
+ $regex = uConfig::passRegex();
+ $this->assertNotRegExp($regex, $password0, "Regex: \"$regex\", password: \"$password0\"");
+ $this->assertRegExp($regex, $password1, "Regex: \"$regex\", password: \"$password1\"");
+ $this->assertRegExp($regex, $password2, "Regex: \"$regex\", password: \"$password2\"");
+ $this->assertRegExp($regex, $password3, "Regex: \"$regex\", password: \"$password3\"");
+
+ uConfig::$pass_strength = 2;
+ $regex = uConfig::passRegex();
+ $this->assertNotRegExp($regex, $password0, "Regex: \"$regex\", password: \"$password0\"");
+ $this->assertNotRegExp($regex, $password1, "Regex: \"$regex\", password: \"$password1\"");
+ $this->assertRegExp($regex, $password2, "Regex: \"$regex\", password: \"$password2\"");
+ $this->assertRegExp($regex, $password3, "Regex: \"$regex\", password: \"$password3\"");
+
+ uConfig::$pass_strength = 3;
+ $regex = uConfig::passRegex();
+ $this->assertNotRegExp($regex, $password0, "Regex: \"$regex\", password: \"$password0\"");
+ $this->assertNotRegExp($regex, $password1, "Regex: \"$regex\", password: \"$password1\"");
+ $this->assertNotRegExp($regex, $password2, "Regex: \"$regex\", password: \"$password2\"");
+ $this->assertRegExp($regex, $password3, "Regex: \"$regex\", password: \"$password3\"");
+
+ $password_len5 = "12345";
+ $password_len10 = "1234567890";
+ uConfig::$pass_lenmin = 5;
+ uConfig::$pass_strength = 0;
+ $regex = uConfig::passRegex();
+ $this->assertRegExp($regex, $password_len5, "Regex: \"$regex\", password: \"$password_len5\"");
+ $this->assertRegExp($regex, $password_len10, "Regex: \"$regex\", password: \"$password_len10\"");
+
+ uConfig::$pass_lenmin = 7;
+ $regex = uConfig::passRegex();
+ $this->assertNotRegExp($regex, $password_len5, "Regex: \"$regex\", password: \"$password_len5\"");
+ $this->assertRegExp($regex, $password_len10, "Regex: \"$regex\", password: \"$password_len10\"");
+
+ uConfig::$pass_lenmin = 12;
+ $regex = uConfig::passRegex();
+ $this->assertNotRegExp($regex, $password_len5, "Regex: \"$regex\", password: \"$password_len5\"");
+ $this->assertNotRegExp($regex, $password_len10, "Regex: \"$regex\", password: \"$password_len10\"");
+ }
+}
+?>
diff --git a/.tests/tests/PositionTest.php b/.tests/tests/PositionTest.php
new file mode 100644
index 0000000..21bcce3
--- /dev/null
+++ b/.tests/tests/PositionTest.php
@@ -0,0 +1,143 @@
+addTestTrack($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $posId = uPosition::add($this->testUserId, $trackId + 1, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($posId, "Adding position with nonexistant track should fail");
+
+ $posId = uPosition::add($this->testUserId2, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($posId, "Adding position with wrong user should fail");
+
+ $posId = uPosition::add($this->testUserId, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $expected = [
+ "id" => $posId,
+ "user_id" => $this->testUserId,
+ "track_id" => $trackId,
+ "time" => $this->testTimestamp,
+ "latitude" => $this->testLat,
+ "longitude" => $this->testLon,
+ "altitude" => $this->testAltitude,
+ "speed" => $this->testSpeed,
+ "bearing" => $this->testBearing,
+ "accuracy" => $this->testAccuracy,
+ "provider" => $this->testProvider,
+ "comment" => $this->testComment,
+ "image_id" => $this->testImageId
+ ];
+ $actual = $this->getConnection()->createQueryTable(
+ "positions",
+ "SELECT id, user_id, track_id, UNIX_TIMESTAMP(time) AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
+ );
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+
+ $posId = uPosition::add($this->testUserId, $trackId, NULL, $this->testLat, $this->testLon);
+ $this->assertFalse($posId, "Adding position with null time stamp should fail");
+ $posId = uPosition::add($this->testUserId, $trackId, $this->testTimestamp, NULL, $this->testLon);
+ $this->assertFalse($posId, "Adding position with null latitude should fail");
+ $posId = uPosition::add($this->testUserId, $trackId, $this->testTimestamp, $this->testLat, NULL);
+ $this->assertFalse($posId, "Adding position with null longitude should fail");
+
+ $posId = uPosition::add($this->testUserId, $trackId, "", $this->testLat, $this->testLon);
+ $this->assertFalse($posId, "Adding position with empty time stamp should fail");
+ $posId = uPosition::add($this->testUserId, $trackId, $this->testTimestamp, "", $this->testLon);
+ $this->assertFalse($posId, "Adding position with empty latitude should fail");
+ $posId = uPosition::add($this->testUserId, $trackId, $this->testTimestamp, $this->testLat, "");
+ $this->assertFalse($posId, "Adding position with empty longitude should fail");
+ }
+
+ public function testDeleteAll() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId);
+ $trackId2 = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId2);
+ $trackId3 = $this->addTestTrack($this->testUserId2);
+ $this->addTestPosition($this->testUserId2, $trackId3);
+ $this->assertEquals(3, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(3, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $this->assertTrue(uPosition::deleteAll($this->testUserId), "Deleting failed");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ }
+
+ public function testDeleteAllWIthTrackId() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId);
+ $trackId2 = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId2);
+ $trackId3 = $this->addTestTrack($this->testUserId2);
+ $this->addTestPosition($this->testUserId2, $trackId3);
+ $this->assertEquals(3, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(3, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $this->assertTrue(uPosition::deleteAll($this->testUserId, $trackId), "Deleting failed");
+ $this->assertEquals(2, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ }
+
+ public function testGetLast() {
+ $trackId1 = $this->addTestTrack($this->testUserId);
+ $trackId2 = $this->addTestTrack($this->testUserId);
+ $pos1 = $this->addTestPosition($this->testUserId, $trackId1, $this->testTimestamp + 3);
+ $pos2 = $this->addTestPosition($this->testUserId2, $trackId2, $this->testTimestamp + 1);
+ $pos3 = $this->addTestPosition($this->testUserId, $trackId1, $this->testTimestamp);
+ $pos4 = $this->addTestPosition($this->testUserId2, $trackId2, $this->testTimestamp + 2);
+ $this->assertEquals(2, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(4, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $lastPosition = uPosition::getLast();
+ $this->assertEquals($lastPosition->id, $pos1, "Wrong last position");
+ $lastPosition = uPosition::getLast($this->testUserId2);
+ $this->assertEquals($lastPosition->id, $pos4, "Wrong last position (user)");
+ }
+
+ public function testGetAll() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId);
+ $trackId2 = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId2);
+ $trackId3 = $this->addTestTrack($this->testUserId2);
+ $this->addTestPosition($this->testUserId2, $trackId3);
+ $this->assertEquals(3, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(3, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $posArr = uPosition::getAll();
+ $this->assertEquals(3, count($posArr), "Wrong row count");
+ $posArr = uPosition::getAll($this->testUserId);
+ $this->assertEquals(2, count($posArr), "Wrong row count");
+ $posArr = uPosition::getAll($this->testUserId, $trackId);
+ $this->assertEquals(1, count($posArr), "Wrong row count");
+ $posArr = uPosition::getAll(NULL, $trackId);
+ $this->assertEquals(1, count($posArr), "Wrong row count");
+ $posArr = uPosition::getAll($this->testUserId3);
+ $this->assertEquals(0, count($posArr), "Wrong row count");
+ }
+
+ public function testDistanceTo() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $pos1 = $this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp, 0, 0);
+ $pos2 = $this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp, 0, 1);
+ $posArr = uPosition::getAll();
+ $this->assertEquals(2, count($posArr), "Wrong row count");
+ $this->assertEquals(111195, round($posArr[0]->distanceTo($posArr[1])), "Wrong distance");
+ }
+
+ public function testSecondsTo() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $pos1 = $this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp);
+ $pos2 = $this->addTestPosition($this->testUserId, $trackId, $this->testTimestamp + 1);
+ $posArr = uPosition::getAll();
+ $this->assertEquals(2, count($posArr), "Wrong row count");
+ $this->assertEquals(-1, $posArr[0]->secondsTo($posArr[1]), "Wrong time difference");
+ }
+
+}
+?>
diff --git a/.tests/tests/TrackTest.php b/.tests/tests/TrackTest.php
new file mode 100644
index 0000000..3ae563c
--- /dev/null
+++ b/.tests/tests/TrackTest.php
@@ -0,0 +1,133 @@
+testUserId, $this->testTrackName, $this->testTrackComment);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(1, $trackId, "Wrong track id returned");
+ $expected = [ "id" => $trackId, "user_id" => $this->testUserId, "name" => $this->testTrackName, "comment" => $this->testTrackComment ];
+ $actual = $this->getConnection()->createQueryTable("tracks", "SELECT id, user_id, name, comment FROM tracks");
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+
+ $this->assertFalse(uTrack::add("", $this->testTrackName), "Adding track with empty user id should fail");
+ $this->assertFalse(uTrack::add($this->testUserId, ""), "Adding track with empty name should fail");
+ }
+
+ public function testDeleteTrack() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->addTestPosition($this->testUserId, $trackId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $track = new uTrack($trackId);
+ $track->delete();
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($track->isValid, "Deleted track should not be valid");
+ }
+
+ public function testAddPosition() {
+ $trackId = $this->addTestTrack($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $track = new uTrack($trackId + 1);
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($posId, "Adding position with nonexistant track should fail");
+
+ $track = new uTrack($trackId);
+ $posId = $track->addPosition($this->testUserId2, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($posId, "Adding position with wrong user should fail");
+
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $expected = [
+ "id" => $posId,
+ "user_id" => $this->testUserId,
+ "track_id" => $trackId,
+ "time" => $this->testTimestamp,
+ "latitude" => $this->testLat,
+ "longitude" => $this->testLon,
+ "altitude" => $this->testAltitude,
+ "speed" => $this->testSpeed,
+ "bearing" => $this->testBearing,
+ "accuracy" => $this->testAccuracy,
+ "provider" => $this->testProvider,
+ "comment" => $this->testComment,
+ "image_id" => $this->testImageId
+ ];
+ $actual = $this->getConnection()->createQueryTable(
+ "positions",
+ "SELECT id, user_id, track_id, UNIX_TIMESTAMP(time) AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions"
+ );
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+
+ $posId = $track->addPosition($this->testUserId, NULL, $this->testLat, $this->testLon);
+ $this->assertFalse($posId, "Adding position with null time stamp should fail");
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, NULL, $this->testLon);
+ $this->assertFalse($posId, "Adding position with null latitude should fail");
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, $this->testLat, NULL);
+ $this->assertFalse($posId, "Adding position with null longitude should fail");
+
+ $posId = $track->addPosition($this->testUserId, "", $this->testLat, $this->testLon);
+ $this->assertFalse($posId, "Adding position with empty time stamp should fail");
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, "", $this->testLon);
+ $this->assertFalse($posId, "Adding position with empty latitude should fail");
+ $posId = $track->addPosition($this->testUserId, $this->testTimestamp, $this->testLat, "");
+ $this->assertFalse($posId, "Adding position with empty longitude should fail");
+ }
+
+ public function testGetAll() {
+ $this->addTestTrack();
+ $this->addTestTrack();
+ $this->assertEquals(2, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+
+ $trackArr = uTrack::getAll();
+ $this->assertEquals(2, count($trackArr), "Wrong array size");
+ $this->assertTrue($trackArr[0] instanceof uTrack, "Wrong array member");
+ }
+
+ public function testDeleteAll() {
+ $trackId = $this->addTestTrack();
+ $this->addTestTrack();
+ $this->addTestPosition($this->testUserId, $trackId);
+
+ $trackId2 = $this->addTestTrack($this->testUserId2);
+ $this->addTestPosition($this->testUserId2, $trackId2);
+
+ $this->assertEquals(3, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(2, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ uTrack::deleteAll($this->testUserId);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse(uTrack::deleteAll(NULL), "User id should not be empty");
+ }
+
+ public function testUpdate() {
+ $trackId = $this->addTestTrack();
+ $track = new uTrack($trackId);
+ $track->update("newName", "newComment");
+ $expected = [ "id" => $trackId, "user_id" => $this->testUserId, "name" => "newName", "comment" => "newComment" ];
+ $actual = $this->getConnection()->createQueryTable("tracks", "SELECT id, user_id, name, comment FROM tracks");
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+
+ $trackInvalid = new uTrack($trackId + 1);
+ $this->assertFalse($trackInvalid->update("newName", "newComment"), "Updating nonexistant track should fail");
+ }
+
+ public function testIsValid() {
+ $trackId = $this->addTestTrack();
+ $trackValid = new uTrack($trackId);
+ $this->assertTrue($trackValid->isValid, "Track should be valid");
+ $trackInvalid = new uTrack($trackId + 1);
+ $this->assertFalse($trackInvalid->isValid, "Track should not be valid");
+ }
+}
+?>
diff --git a/.tests/tests/UserTest.php b/.tests/tests/UserTest.php
new file mode 100644
index 0000000..3ba4af5
--- /dev/null
+++ b/.tests/tests/UserTest.php
@@ -0,0 +1,81 @@
+testUser, $this->testPass);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ $this->assertEquals(1, $userId, "Wrong user id returned");
+ $expected = [ "id" => 1, "login" => $this->testUser ];
+ $actual = $this->getConnection()->createQueryTable("users", "SELECT id, login FROM users");
+ $this->assertTableContains($expected, $actual, "Wrong actual table data");
+
+ $this->assertTrue(password_verify($this->testPass, $this->pdoGetColumn("SELECT password FROM users")), "Wrong actual password hash");
+ $this->assertFalse(uUser::add($this->testUser, $this->testPass), "Adding user with same login should fail");
+ $this->assertFalse(uUser::add($this->testUser, ""), "Adding user with empty password should fail");
+ $this->assertFalse(uUser::add("", $this->testPass), "Adding user with empty login should fail");
+ }
+
+ public function testDeleteUser() {
+ $userId = $this->addTestUser($this->testUser);
+ $trackId = $this->addTestTrack($userId);
+ $this->addTestPosition($userId, $trackId);
+
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+
+ $user = new uUser($this->testUser);
+ $user->delete();
+ $this->assertEquals(0, $this->getConnection()->getRowCount('users'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('tracks'), "Wrong row count");
+ $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count");
+ $this->assertFalse($user->isValid, "Deleted user should not be valid");
+ }
+
+ public function testSetPass() {
+ $newPass = $this->testPass . "new";
+ $this->addTestUser($this->testUser);
+ $this->assertEquals(1, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $user = new uUser($this->testUser);
+ $user->setPass($newPass);
+ $this->assertTrue(password_verify($newPass, $this->pdoGetColumn("SELECT password FROM users")), "Wrong actual password hash");
+ $this->assertFalse($user->setPass(""), "Password should not be empty");
+
+ $userInvalid = new uUser($this->testUser . "-noexistant");
+ $this->assertFalse($userInvalid->setPass($newPass), "Setting pass for nonexistant user should fail");
+ }
+
+ public function testGetAll() {
+ $this->addTestUser($this->testUser);
+ $this->addTestUser($this->testUser2);
+ $this->assertEquals(2, $this->getConnection()->getRowCount('users'), "Wrong row count");
+
+ $userArr = uUser::getAll();
+ $this->assertEquals(2, count($userArr), "Wrong array size");
+ $this->assertTrue($userArr[0] instanceof uUser, "Wrong array member");
+ }
+
+ public function testIsAdmin() {
+ $this->addTestUser($this->testUser);
+ $user = new uUser($this->testUser);
+ $this->assertFalse($user->isAdmin, "User should not be admin");
+ uConfig::$admin_user = $this->testUser;
+ $user = new uUser($this->testUser);
+ $this->assertTrue($user->isAdmin, "User should be admin");
+ }
+
+ public function testIsValid() {
+ $this->addTestUser($this->testUser);
+ $userValid = new uUser($this->testUser);
+ $this->assertTrue($userValid->isValid, "User should be valid");
+ $userInvalid = new uUser($this->testUser . "-noexistant");
+ $this->assertFalse($userInvalid->isValid, "User should not be valid");
+ }
+}
+?>
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6afa12a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,26 @@
+language: php
+
+sudo: required
+
+php:
+ - 7.0
+
+env:
+ - DB_HOST="localhost"
+ - DB_NAME="ulogger"
+ - DB_USER="ulogger"
+ - DB_PASS="secret2"
+ - DB_PORT=8081
+ - ULOGGER_URL="http://127.0.0.1:8080"
+
+services:
+ - docker
+
+before_install:
+ - docker build -t ulogger .
+ - docker run -d --name ulogger -p 8080:80 -p 8081:3306 --expose 3306 ulogger
+ - composer install
+ - until netstat -atn 2>/dev/null | grep '8080.*LISTEN'; do sleep 1; done
+
+script:
+ - ./vendor/bin/phpunit -c .tests/phpunit.xml
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..d8c9c56
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,13 @@
+{
+ "require": {
+ "phpunit/phpunit": "^5.7",
+ "vlucas/phpdotenv": "^2.4",
+ "guzzlehttp/guzzle": "^6.3"
+ },
+ "scripts": {
+ "test": "./vendor/bin/phpunit"
+ },
+ "require-dev": {
+ "phpunit/dbunit": "^2.0"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..d3e068e
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,1668 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "2d8c5cc5e1d061a121d0f1dc7a602ac4",
+ "packages": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3,<8.0-DEV"
+ },
+ "require-dev": {
+ "athletic/athletic": "~0.1.8",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://github.com/doctrine/instantiator",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "time": "2015-06-14T21:17:01+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
+ "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.4",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "psr/log": "^1.0"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.2-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "time": "2017-06-22T18:50:49+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "v1.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "time": "2016-12-20T10:07:11+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "time": "2017-03-20T17:10:46+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102",
+ "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "doctrine/collections": "1.*",
+ "phpunit/phpunit": "~4.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "homepage": "https://github.com/myclabs/DeepCopy",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "time": "2017-04-12T18:52:22+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "time": "2015-12-27T11:43:31+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "3.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157",
+ "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5",
+ "phpdocumentor/reflection-common": "^1.0@dev",
+ "phpdocumentor/type-resolver": "^0.3.0",
+ "webmozart/assert": "^1.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.4",
+ "phpunit/phpunit": "^4.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "time": "2017-08-08T06:39:58+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773",
+ "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.5 || ^7.0",
+ "phpdocumentor/reflection-common": "^1.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.4",
+ "phpunit/phpunit": "^5.2||^4.8.24"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "time": "2017-06-03T08:32:36+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
+ "sebastian/comparator": "^1.1|^2.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5|^3.2",
+ "phpunit/phpunit": "^4.8 || ^5.6.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Prophecy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "time": "2017-03-02T20:05:34+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "4.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
+ "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xmlwriter": "*",
+ "php": "^5.6 || ^7.0",
+ "phpunit/php-file-iterator": "^1.3",
+ "phpunit/php-text-template": "^1.2",
+ "phpunit/php-token-stream": "^1.4.2 || ^2.0",
+ "sebastian/code-unit-reverse-lookup": "^1.0",
+ "sebastian/environment": "^1.3.2 || ^2.0",
+ "sebastian/version": "^1.0 || ^2.0"
+ },
+ "require-dev": {
+ "ext-xdebug": "^2.1.4",
+ "phpunit/phpunit": "^5.7"
+ },
+ "suggest": {
+ "ext-xdebug": "^2.5.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2017-04-02T07:44:40+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2016-10-03T07:40:28+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2015-06-21T13:50:34+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2017-02-26T11:10:40+00:00"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "1.4.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2017-02-27T10:12:30+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "5.7.21",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "3b91adfb64264ddec5a2dee9851f354aa66327db"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3b91adfb64264ddec5a2dee9851f354aa66327db",
+ "reference": "3b91adfb64264ddec5a2dee9851f354aa66327db",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "myclabs/deep-copy": "~1.3",
+ "php": "^5.6 || ^7.0",
+ "phpspec/prophecy": "^1.6.2",
+ "phpunit/php-code-coverage": "^4.0.4",
+ "phpunit/php-file-iterator": "~1.4",
+ "phpunit/php-text-template": "~1.2",
+ "phpunit/php-timer": "^1.0.6",
+ "phpunit/phpunit-mock-objects": "^3.2",
+ "sebastian/comparator": "^1.2.4",
+ "sebastian/diff": "^1.4.3",
+ "sebastian/environment": "^1.3.4 || ^2.0",
+ "sebastian/exporter": "~2.0",
+ "sebastian/global-state": "^1.1",
+ "sebastian/object-enumerator": "~2.0",
+ "sebastian/resource-operations": "~1.0",
+ "sebastian/version": "~1.0.3|~2.0",
+ "symfony/yaml": "~2.1|~3.0"
+ },
+ "conflict": {
+ "phpdocumentor/reflection-docblock": "3.0.2"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
+ },
+ "suggest": {
+ "ext-xdebug": "*",
+ "phpunit/php-invoker": "~1.1"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.7.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2017-06-21T08:11:54+00:00"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "3.4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "a23b761686d50a560cc56233b9ecf49597cc9118"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118",
+ "reference": "a23b761686d50a560cc56233b9ecf49597cc9118",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.6 || ^7.0",
+ "phpunit/php-text-template": "^1.2",
+ "sebastian/exporter": "^1.2 || ^2.0"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.4"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "time": "2017-06-30T09:13:00+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "time": "2016-08-06T14:39:51+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "time": "2017-03-04T06:30:41+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "1.2.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "sebastian/diff": "~1.2",
+ "sebastian/exporter": "~1.2 || ~2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "time": "2017-01-29T09:50:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "1.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff"
+ ],
+ "time": "2017-05-22T07:24:03+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
+ "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "time": "2016-11-26T07:53:53+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
+ "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "sebastian/recursion-context": "~2.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "time": "2016-11-19T08:54:04+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.2"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "time": "2015-10-12T03:26:01+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
+ "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6",
+ "sebastian/recursion-context": "~2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "time": "2017-02-18T15:18:39+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
+ "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "time": "2016-11-19T07:33:16+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "time": "2015-07-28T20:34:47+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "time": "2016-10-03T07:35:21+00:00"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v3.3.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
+ "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.9"
+ },
+ "require-dev": {
+ "symfony/console": "~2.8|~3.0"
+ },
+ "suggest": {
+ "symfony/console": "For validating YAML files using the lint command"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Yaml\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Yaml Component",
+ "homepage": "https://symfony.com",
+ "time": "2017-07-23T12:43:26+00:00"
+ },
+ {
+ "name": "vlucas/phpdotenv",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vlucas/phpdotenv.git",
+ "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
+ "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8 || ^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dotenv\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause-Attribution"
+ ],
+ "authors": [
+ {
+ "name": "Vance Lucas",
+ "email": "vance@vancelucas.com",
+ "homepage": "http://www.vancelucas.com"
+ }
+ ],
+ "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+ "keywords": [
+ "dotenv",
+ "env",
+ "environment"
+ ],
+ "time": "2016-09-01T10:05:43+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
+ "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6",
+ "sebastian/version": "^1.0.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "time": "2016-11-23T20:04:58+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "phpunit/dbunit",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/dbunit.git",
+ "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5c35d74549c21ba55d0ea74ba89d191a51f8cf25",
+ "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25",
+ "shasum": ""
+ },
+ "require": {
+ "ext-pdo": "*",
+ "ext-simplexml": "*",
+ "php": "^5.4 || ^7.0",
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0",
+ "symfony/yaml": "^2.1 || ^3.0"
+ },
+ "bin": [
+ "dbunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.",
+ "homepage": "https://github.com/sebastianbergmann/dbunit/",
+ "keywords": [
+ "database",
+ "testing",
+ "xunit"
+ ],
+ "time": "2016-12-02T14:39:14+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": []
+}