summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--includes/controller/api.php355
-rw-r--r--includes/engelsystem_provider.php3
-rw-r--r--includes/helper/session_helper.php2
-rw-r--r--includes/model/Room_model.php34
-rw-r--r--includes/pages/admin_import.php4
-rw-r--r--includes/pages/admin_rooms.php96
-rw-r--r--public/index.php3
-rw-r--r--test/model/Room_model_test.php32
-rw-r--r--test/phpunit.xml11
10 files changed, 127 insertions, 414 deletions
diff --git a/.gitignore b/.gitignore
index 30785b84..f0e37b9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
_vimrc_local.vim
.sass-cache
config/config.php
+test/coverage
diff --git a/includes/controller/api.php b/includes/controller/api.php
deleted file mode 100644
index 9ecd3a2f..00000000
--- a/includes/controller/api.php
+++ /dev/null
@@ -1,355 +0,0 @@
-<?php
-
-/************************************************************************************************
- * API Documentation
- ************************************************************************************************
-
-General:
---------
-All API calls output JSON-encoded data. Client parameters should be passed encoded using JSON in HTTP POST data.
-Every API Request must be contained the Api Key (using JSON parameter 'key') and the Command (using JSON parameter 'cmd').
-
-
-Testing API calls (using curl):
--------------------------------
-$ curl -d '{"cmd":"getVersion"}' '<Address>/?p=api'
-$ curl -d '{"cmd":"getApiKey","user":"admin","pw":"admin"}' '<Address>/?p=api'
-$ curl -d '{"key":"<key>","cmd":"getRoom"}' '<Address>/?p=api'
-$ curl -d '{"key":"<key>","cmd":"sendmessage","uid":"23","text":"test message"}' '<Address>/?p=api'
-
-Methods without key:
---------------------
-getVersion
- Description:
- Returns API version.
- Parameters:
- nothing
- Return Example:
- {"status":"success","version": "1"}
-
-getApiKey
- Description:
- Returns API Key version.
- Parameters:
- user (string)
- pw (string)
- Return Example:
- {"status":"success","Key":"1234567890123456789012"}
-
-Methods with Key:
------------------
-getRoom
- Description:
- Returns a list of all Rooms (no id set) or details of a single Room (requested id)
- Parameters:
- id (integer) - Room ID
- Return Example:
- [{"RID":"1"},{"RID":"23"},{"RID":"42"}]
- {"RID":"1","Name":"Room Name","Man":null,"FromPentabarf":"","show":"Y","Number":"0"}
-
-getAngelType
- Description:
- Returns a list of all Angel Types (no id set) or details of a single Angel Type (requested id)
- Parameters:
- id (integer) - Type ID
- Return Example:
- [{"id":"8"},{"id":"9"}]
- {"id":"9","name":"Angeltypes 2","restricted":"0"}
-
-getUser
- Description:
- Returns a list of all Users (no id set) or details of a single User (requested id)
- Parameters:
- id (integer) - User ID
- Return Example:
- [{"UID":"1"},{"UID":"23"},{"UID":"42"}]
- {"UID":"1","Nick":"admin","Name":"Gates","Vorname":"Bill","Telefon":"","DECT":"","Handy":"","email":"","jabber":"","Avatar":"115"}
-
-getShift
- Description:
- Returns a list of all Shifte (no id set, filter is optional) or details of a single Shift (requested id)
- Parameters:
- id (integer) - Shift ID
- filterRoom (Array of integer) - Array of Room IDs (optional, for list request)
- filterTask (Array of integer) - Array if Task (optional, for list request)
- filterOccupancy (integer) - Occupancy state: (optional, for list request)
- 1 occupied
- 2 free
- 3 occupied and free
- Return Example:
- [{"SID":"1"},{"SID":"2"},{"SID":"3"}]
- {"SID":"10","start":"1388264400","end":"1388271600","RID":"1","name":"Shift 1","URL":null,"PSID":null,\
- "ShiftEntry":[{"TID":"8","UID":"4","freeloaded":"0"}],
- "NeedAngels":[{"TID":"8","count":"1","restricted":"0","taken":1},{"TID":"9","count":"2","restricted":"0","taken":0}]}
-
-getMessage
- Description:
- Returns a list of all Messages (no id set) or details of a single Message (requested id)
- Parameters:
- id (integer) - Message ID
- Return Example:
- [{"id":"1"},{"id":"2"},{"id":"3"}]
- {"id":"3","Datum":"1388247583","SUID":"23","RUID":"42","isRead":"N","Text":"message text"}
-
-sendMessage
- Description:
- send a Message to an other angel
- Parameters:
- uid (integer) - User ID of the reciever
- text (string) - Message Text
- Return Example:
- {"status":"success"}
-
-************************************************************************************************/
-
-/**
- * General API Controller
- */
-function api_controller() {
- global $user, $DataJson;
-
- header("Content-Type: application/json; charset=utf-8");
-
- // decode JSON request
- $input = file_get_contents("php://input");
- $input = json_decode($input, true);
- $_REQUEST = $input;
-
- // get command
- $cmd = '';
- if (isset($_REQUEST['cmd']))
- $cmd = strtolower($_REQUEST['cmd']);
-
- // decode commands, without key
- switch ($cmd) {
- case 'getversion':
- getVersion();
- die(json_encode($DataJson));
- break;
- case 'getapikey':
- getApiKey();
- die(json_encode($DataJson));
- break;
- }
-
- // get API KEY
- if (isset($_REQUEST['key']) && preg_match("/^[0-9a-f]{32}$/", $_REQUEST['key']))
- $key = $_REQUEST['key'];
- else
- die(json_encode(array(
- 'status' => 'failed',
- 'error' => 'Missing parameter "key".'
- )));
-
- // check API key
- $user = User_by_api_key($key);
- if ($user === false)
- die(json_encode(array(
- 'status' => 'failed',
- 'error' => 'Unable to find user'
- )));
- if ($user == null)
- die(json_encode(array(
- 'status' => 'failed',
- 'error' => 'Key invalid.'
- )));
-
- // decode command
- switch ($cmd) {
- case 'getroom':
- getRoom();
- break;
- case 'getangeltype':
- getAngelType();
- break;
- case 'getuser':
- // TODO Dataleak! Only coordinators are allowed to see so much user informations.
- //getUser();
- break;
- case 'getshift':
- getShift();
- break;
- case 'getmessage':
- // TODO Dataleak!
- //getMessage();
- break;
- case 'sendmessage':
- sendMessage();
- break;
- default:
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Unknown Command "' . $cmd . '"'
- );
- }
-
- // check
- if ($DataJson === false) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'DataJson === false'
- );
- } elseif ($DataJson == null) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'DataJson == null'
- );
- }
-
- echo json_encode($DataJson);
- die();
-}
-
-/**
- * Get Version of API
- */
-function getVersion() {
- global $DataJson;
-
- $DataJson = array(
- 'status' => 'success',
- 'Version' => 1
- );
-}
-
-/**
- * Get API Key
- */
-function getApiKey() {
- global $DataJson;
-
- if (! isset($_REQUEST['user'])) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Missing parameter "user".'
- );
- } elseif (! isset($_REQUEST['pw'])) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Missing parameter "pw".'
- );
- } else {
- $Erg = sql_select("SELECT `UID`, `Passwort`, `api_key` FROM `User` WHERE `Nick`='" . sql_escape($_REQUEST['user']) . "'");
-
- if (count($Erg) == 1) {
- $Erg = $Erg[0];
- if (verify_password($_REQUEST['pw'], $Erg["Passwort"], $Erg["UID"])) {
- $key = $Erg["api_key"];
- $DataJson = array(
- 'status' => 'success',
- 'Key' => $key
- );
- } else {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'PW wrong'
- );
- }
- } else {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'User not found.'
- );
- }
- }
-
- sleep(1);
-}
-
-/**
- * Get Room
- */
-function getRoom() {
- global $DataJson;
-
- if (isset($_REQUEST['id'])) {
- $DataJson = Room($_REQUEST['id']);
- } else {
- $DataJson = Room_ids();
- }
-}
-
-/**
- * Get AngelType
- */
-function getAngelType() {
- global $DataJson;
-
- if (isset($_REQUEST['id'])) {
- $DataJson = AngelType($_REQUEST['id']);
- } else {
- $DataJson = AngelType_ids();
- }
-}
-
-/**
- * Get User
- */
-function getUser() {
- global $DataJson;
-
- if (isset($_REQUEST['id'])) {
- $DataJson = mUser_Limit($_REQUEST['id']);
- } else {
- $DataJson = User_ids();
- }
-}
-
-/**
- * Get Shift
- */
-function getShift() {
- global $DataJson;
-
- if (isset($_REQUEST['id'])) {
- $DataJson = Shift($_REQUEST['id']);
- } else {
- $DataJson = Shifts_filtered();
- }
-}
-
-/**
- * @TODO: Why are ALL messages of ALL users returned? Data leak. It is not checked if this is my message!
- * Get Message
- */
-function getMessage() {
- global $DataJson;
-
- if (isset($_REQUEST['id'])) {
- $DataJson = Message($_REQUEST['id']);
- } else {
- $DataJson = Message_ids();
- }
-}
-
-/**
- * Send Message
- */
-function sendMessage() {
- global $DataJson;
-
- if (! isset($_REQUEST['uid'])) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Missing parameter "uid".'
- );
- } elseif (! isset($_REQUEST['text'])) {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Missing parameter "text".'
- );
- } else {
- if (Message_send($_REQUEST['uid'], $_REQUEST['text']) === true) {
- $DataJson = array(
- 'status' => 'success'
- );
- } else {
- $DataJson = array(
- 'status' => 'failed',
- 'error' => 'Transmitting was terminated with an Error.'
- );
- }
- }
-}
-
-?>
diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php
index 56d12de6..cbc1cb1d 100644
--- a/includes/engelsystem_provider.php
+++ b/includes/engelsystem_provider.php
@@ -71,9 +71,6 @@ require_once realpath(__DIR__ . '/../includes/pages/user_shifts.php');
require_once realpath(__DIR__ . '/../vendor/parsedown/Parsedown.php');
-session_lifetime(24 * 60, preg_replace("/[^a-z0-9-]/", '', md5(__DIR__)));
-session_start();
-
gettext_init();
sql_connect($config['host'], $config['user'], $config['pw'], $config['db']);
diff --git a/includes/helper/session_helper.php b/includes/helper/session_helper.php
index 4063ff69..7a3b551e 100644
--- a/includes/helper/session_helper.php
+++ b/includes/helper/session_helper.php
@@ -22,7 +22,7 @@ function session_lifetime($lifetime, $application_name) {
ini_set('session.gc_divisor', 100);
// Cookie settings (lifetime)
- ini_set('session.cookie_secure', ! (preg_match("/^localhost/", $_SERVER["HTTP_HOST"]) || isset($_GET['debug'])));
+ ini_set('session.cookie_secure', ! (isset($_SERVER['HTTP_HOST']) && preg_match("/^localhost/", $_SERVER["HTTP_HOST"]) || isset($_GET['debug'])));
ini_set('session.use_only_cookies', true);
ini_set('session.cookie_lifetime', $lifetime * 60);
}
diff --git a/includes/model/Room_model.php b/includes/model/Room_model.php
index 523436c6..2868916e 100644
--- a/includes/model/Room_model.php
+++ b/includes/model/Room_model.php
@@ -1,15 +1,33 @@
<?php
/**
- * Returns room id array
+ * Delete a room
+ * @param int $room_id
*/
-function Room_ids() {
- $room_source = sql_select("SELECT `RID` FROM `Room` WHERE `show` = 'Y'");
- if ($room_source === false)
+function Room_delete($room_id) {
+ return sql_query("DELETE FROM `Room` WHERE `RID`=" . sql_escape($room_id));
+}
+
+/**
+ * Create a new room
+ *
+ * @param string $name
+ * Name of the room
+ * @param boolean $from_frab
+ * Is this a frab imported room?
+ * @param boolean $public
+ * Is the room visible for angels?
+ */
+function Room_create($name, $from_frab, $public) {
+ $result = sql_query("
+ INSERT INTO `Room` SET
+ `Name`='" . sql_escape($name) . "',
+ `FromPentabarf`='" . sql_escape($from_frab ? 'Y' : 'N') . "',
+ `show`='" . sql_escape($public ? 'Y' : 'N') . "',
+ `Number`=0");
+ if ($result === false)
return false;
- if (count($room_source) > 0)
- return $room_source;
- return null;
+ return sql_id();
}
/**
@@ -18,7 +36,7 @@ function Room_ids() {
* @param $id RID
*/
function Room($id) {
- $room_source = sql_select("SELECT * FROM `Room` WHERE `RID`='" . sql_escape($id) . "' AND `show` = 'Y' LIMIT 1");
+ $room_source = sql_select("SELECT * FROM `Room` WHERE `RID`='" . sql_escape($id) . "' AND `show` = 'Y'");
if ($room_source === false)
return false;
diff --git a/includes/pages/admin_import.php b/includes/pages/admin_import.php
index 786ea08b..0ed2bea9 100644
--- a/includes/pages/admin_import.php
+++ b/includes/pages/admin_import.php
@@ -162,7 +162,9 @@ function admin_import() {
list($rooms_new, $rooms_deleted) = prepare_rooms($import_file);
foreach ($rooms_new as $room) {
- sql_query("INSERT INTO `Room` SET `Name`='" . sql_escape($room) . "', `FromPentabarf`='Y', `Show`='Y'");
+ $result = Room_create($name, true, true);
+ if ($result === false)
+ engelsystem_error('Unable to create room.');
$rooms_import[trim($room)] = sql_id();
}
foreach ($rooms_deleted as $room)
diff --git a/includes/pages/admin_rooms.php b/includes/pages/admin_rooms.php
index 777ff6be..7f2e3db0 100644
--- a/includes/pages/admin_rooms.php
+++ b/includes/pages/admin_rooms.php
@@ -1,11 +1,12 @@
<?php
+
function admin_rooms_title() {
return _("Rooms");
}
function admin_rooms() {
global $user;
-
+
$rooms_source = sql_select("SELECT * FROM `Room` ORDER BY `Name`");
$rooms = array();
foreach ($rooms_source as $room)
@@ -15,17 +16,17 @@ function admin_rooms() {
'public' => $room['show'] == 'Y' ? '&#10003;' : '',
'actions' => buttons(array(
button(page_link_to('admin_rooms') . '&show=edit&id=' . $room['RID'], _("edit"), 'btn-xs'),
- button(page_link_to('admin_rooms') . '&show=delete&id=' . $room['RID'], _("delete"), 'btn-xs')
- ))
+ button(page_link_to('admin_rooms') . '&show=delete&id=' . $room['RID'], _("delete"), 'btn-xs')
+ ))
);
-
+
if (isset($_REQUEST['show'])) {
$msg = "";
$name = "";
$from_pentabarf = "";
$public = 'Y';
$number = "";
-
+
$angeltypes_source = sql_select("SELECT * FROM `AngelTypes` ORDER BY `name`");
$angeltypes = array();
$angeltypes_count = array();
@@ -33,7 +34,7 @@ function admin_rooms() {
$angeltypes[$angeltype['id']] = $angeltype['name'];
$angeltypes_count[$angeltype['id']] = 0;
}
-
+
if (test_request_int('id')) {
$room = sql_select("SELECT * FROM `Room` WHERE `RID`='" . sql_escape($_REQUEST['id']) . "'");
if (count($room) > 0) {
@@ -47,33 +48,33 @@ function admin_rooms() {
} else
redirect(page_link_to('admin_rooms'));
}
-
+
if ($_REQUEST['show'] == 'edit') {
if (isset($_REQUEST['submit'])) {
$ok = true;
-
+
if (isset($_REQUEST['name']) && strlen(strip_request_item('name')) > 0)
$name = strip_request_item('name');
else {
$ok = false;
$msg .= error(_("Please enter a name."), true);
}
-
+
if (isset($_REQUEST['from_pentabarf']))
$from_pentabarf = 'Y';
else
$from_pentabarf = '';
-
+
if (isset($_REQUEST['public']))
$public = 'Y';
else
$public = '';
-
+
if (isset($_REQUEST['number']))
$number = strip_request_item('number');
else
$ok = false;
-
+
foreach ($angeltypes as $angeltype_id => $angeltype) {
if (isset($_REQUEST['angeltype_count_' . $angeltype_id]) && preg_match("/^[0-9]{1,4}$/", $_REQUEST['angeltype_count_' . $angeltype_id]))
$angeltypes_count[$angeltype_id] = $_REQUEST['angeltype_count_' . $angeltype_id];
@@ -82,17 +83,18 @@ function admin_rooms() {
$msg .= error(sprintf(_("Please enter needed angels for type %s.", $angeltype)), true);
}
}
-
+
if ($ok) {
if (isset($id)) {
sql_query("UPDATE `Room` SET `Name`='" . sql_escape($name) . "', `FromPentabarf`='" . sql_escape($from_pentabarf) . "', `show`='" . sql_escape($public) . "', `Number`='" . sql_escape($number) . "' WHERE `RID`='" . sql_escape($id) . "' LIMIT 1");
engelsystem_log("Room updated: " . $name . ", pentabarf import: " . $from_pentabarf . ", public: " . $public . ", number: " . $number);
} else {
- sql_query("INSERT INTO `Room` SET `Name`='" . sql_escape($name) . "', `FromPentabarf`='" . sql_escape($from_pentabarf) . "', `show`='" . sql_escape($public) . "', `Number`='" . sql_escape($number) . "'");
- $id = sql_id();
+ $id = Room_create($name, $from_pentabarf, $public, $number);
+ if ($id === false)
+ engelsystem_error("Unable to create room.");
engelsystem_log("Room created: " . $name . ", pentabarf import: " . $from_pentabarf . ", public: " . $public . ", number: " . $number);
}
-
+
sql_query("DELETE FROM `NeededAngelTypes` WHERE `room_id`='" . sql_escape($id) . "'");
$needed_angeltype_info = array();
foreach ($angeltypes_count as $angeltype_id => $angeltype_count) {
@@ -102,7 +104,7 @@ function admin_rooms() {
$needed_angeltype_info[] = $angeltypes_source[0]['name'] . ": " . $angeltype_count;
}
}
-
+
engelsystem_log("Set needed angeltypes of room " . $name . " to: " . join(", ", $needed_angeltype_info));
success(_("Room saved."));
redirect(page_link_to("admin_rooms"));
@@ -110,66 +112,68 @@ function admin_rooms() {
}
$angeltypes_count_form = array();
foreach ($angeltypes as $angeltype_id => $angeltype)
- $angeltypes_count_form[] = div('col-lg-4 col-md-6 col-xs-6', array(form_spinner('angeltype_count_' . $angeltype_id, $angeltype, $angeltypes_count[$angeltype_id])));
-
+ $angeltypes_count_form[] = div('col-lg-4 col-md-6 col-xs-6', array(
+ form_spinner('angeltype_count_' . $angeltype_id, $angeltype, $angeltypes_count[$angeltype_id])
+ ));
+
return page_with_title(admin_rooms_title(), array(
buttons(array(
- button(page_link_to('admin_rooms'), _("back"), 'back')
+ button(page_link_to('admin_rooms'), _("back"), 'back')
)),
$msg,
form(array(
- div('row', array(
- div('col-md-6', array(
- form_text('name', _("Name"), $name),
- form_checkbox('from_pentabarf', _("Frab import"), $from_pentabarf),
- form_checkbox('public', _("Public"), $public),
- form_text('number', _("Room number"), $number)
- )),
- div('col-md-6', array(
- div('row', array(
- div('col-md-12', array(
- form_info(_("Needed angels:")),
+ div('row', array(
+ div('col-md-6', array(
+ form_text('name', _("Name"), $name),
+ form_checkbox('from_pentabarf', _("Frab import"), $from_pentabarf),
+ form_checkbox('public', _("Public"), $public),
+ form_text('number', _("Room number"), $number)
)),
- join($angeltypes_count_form)
- ))
- ))
- )),
- form_submit('submit', _("Save"))
- ))
+ div('col-md-6', array(
+ div('row', array(
+ div('col-md-12', array(
+ form_info(_("Needed angels:"))
+ )),
+ join($angeltypes_count_form)
+ ))
+ ))
+ )),
+ form_submit('submit', _("Save"))
+ ))
));
} elseif ($_REQUEST['show'] == 'delete') {
if (isset($_REQUEST['ack'])) {
sql_query("DELETE FROM `Room` WHERE `RID`='" . sql_escape($id) . "' LIMIT 1");
sql_query("DELETE FROM `NeededAngelTypes` WHERE `room_id`='" . sql_escape($id) . "' LIMIT 1");
-
+
engelsystem_log("Room deleted: " . $name);
success(sprintf(_("Room %s deleted."), $name));
redirect(page_link_to('admin_rooms'));
}
-
+
return page_with_title(admin_rooms_title(), array(
buttons(array(
- button(page_link_to('admin_rooms'), _("back"), 'back')
+ button(page_link_to('admin_rooms'), _("back"), 'back')
)),
sprintf(_("Do you want to delete room %s?"), $name),
buttons(array(
- button(page_link_to('admin_rooms') . '&show=delete&id=' . $id . '&ack', _("Delete"), 'delete')
- ))
+ button(page_link_to('admin_rooms') . '&show=delete&id=' . $id . '&ack', _("Delete"), 'delete')
+ ))
));
}
}
-
+
return page_with_title(admin_rooms_title(), array(
buttons(array(
- button(page_link_to('admin_rooms') . '&show=edit', _("add"))
+ button(page_link_to('admin_rooms') . '&show=edit', _("add"))
)),
msg(),
table(array(
'name' => _("Name"),
'from_pentabarf' => _("Frab import"),
'public' => _("Public"),
- 'actions' => ""
- ), $rooms)
+ 'actions' => ""
+ ), $rooms)
));
}
?>
diff --git a/public/index.php b/public/index.php
index 418b7eea..d69c4361 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,6 +1,9 @@
<?php
require_once realpath(__DIR__ . '/../includes/engelsystem_provider.php');
+session_lifetime(24 * 60, preg_replace("/[^a-z0-9-]/", '', md5(__DIR__)));
+session_start();
+
// JSON Authorisierung gewünscht?
if (isset($_REQUEST['auth']))
json_auth_service();
diff --git a/test/model/Room_model_test.php b/test/model/Room_model_test.php
new file mode 100644
index 00000000..d95c5787
--- /dev/null
+++ b/test/model/Room_model_test.php
@@ -0,0 +1,32 @@
+<?php
+
+class Room_model_test extends PHPUnit_Framework_TestCase {
+
+ private $room_id = null;
+
+ public function create_Room() {
+ $this->room_id = Room_create('test', false, true, '');
+ }
+
+ public function test_Room() {
+ $this->create_Room();
+
+ $room = Room($this->room_id);
+
+ $this->assertNotFalse($room);
+ $this->assertNotNull($room);
+ $this->assertEquals($room['Name'], 'test');
+
+ $this->assertNull(Room(- 1));
+ }
+
+ /**
+ * @after
+ */
+ public function teardown() {
+ if ($this->room_id != null)
+ Room_delete($this->room_id);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/test/phpunit.xml b/test/phpunit.xml
new file mode 100644
index 00000000..a2c020ff
--- /dev/null
+++ b/test/phpunit.xml
@@ -0,0 +1,11 @@
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.0/phpunit.xsd"
+ bootstrap="../includes/engelsystem_provider.php" colors="true" convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true" convertWarningsToExceptions="true"
+ forceCoversAnnotation="false">
+ <testsuites>
+ <testsuite name="Models">
+ <directory>model</directory>
+ </testsuite>
+ </testsuites>
+</phpunit>