From 7ea2352ca3e444452d05d282a85546fcb35863fd Mon Sep 17 00:00:00 2001 From: "paul.baranowski" Date: Tue, 14 Sep 2010 10:18:53 -0400 Subject: [PATCH] Started to put metadata into the files table. Gave the table sequences their own config values in $CC_CONFIG. This allows us to change their names from one single place. Fixed WHITE_SCREEN_OF_DEATH warnings. Added PHPUnit to the pear library. Started adding unit tests in storageServer/var/tests. --- bin/upgrade-1.3-to-1.4.sql | 33 + src/modules/alib/var/Alib.php | 2 +- src/modules/alib/var/Subjects.php | 4 +- src/modules/storageServer/var/BasicStor.php | 149 ++-- src/modules/storageServer/var/DataEngine.php | 115 +-- src/modules/storageServer/var/GreenBox.php | 18 +- src/modules/storageServer/var/LocStor.php | 6 +- src/modules/storageServer/var/MetaData.php | 44 +- src/modules/storageServer/var/Prefs.php | 2 +- src/modules/storageServer/var/StoredFile.php | 144 +++- src/modules/storageServer/var/Transport.php | 124 +-- .../storageServer/var/TransportRecord.php | 2 +- src/modules/storageServer/var/conf.php | 9 +- .../storageServer/var/install/install.php | 143 ++-- .../storageServer/var/install/uninstall.php | 28 +- .../storageServer/var/tests/UnitTests.php | 86 ++ .../storageServer/var/tests/runUnitTests.php | 9 + .../storageServer/var/tests/transTest.php | 2 - src/tools/pear/src/PHPUnit.php | 132 ++++ src/tools/pear/src/PHPUnit/Assert.php | 426 ++++++++++ src/tools/pear/src/PHPUnit/GUI/Gtk.php | 740 ++++++++++++++++++ src/tools/pear/src/PHPUnit/GUI/HTML.php | 252 ++++++ src/tools/pear/src/PHPUnit/GUI/HTML.tpl | 156 ++++ .../pear/src/PHPUnit/GUI/SetupDecorator.php | 209 +++++ src/tools/pear/src/PHPUnit/RepeatedTest.php | 154 ++++ src/tools/pear/src/PHPUnit/Skeleton.php | 448 +++++++++++ src/tools/pear/src/PHPUnit/TestCase.php | 293 +++++++ src/tools/pear/src/PHPUnit/TestDecorator.php | 156 ++++ src/tools/pear/src/PHPUnit/TestFailure.php | 130 +++ src/tools/pear/src/PHPUnit/TestListener.php | 162 ++++ src/tools/pear/src/PHPUnit/TestResult.php | 347 ++++++++ src/tools/pear/src/PHPUnit/TestSuite.php | 262 +++++++ src/tools/pear/src/VERSIONS.txt | 2 + 33 files changed, 4423 insertions(+), 366 deletions(-) create mode 100644 src/modules/storageServer/var/tests/UnitTests.php create mode 100644 src/modules/storageServer/var/tests/runUnitTests.php create mode 100644 src/tools/pear/src/PHPUnit.php create mode 100644 src/tools/pear/src/PHPUnit/Assert.php create mode 100644 src/tools/pear/src/PHPUnit/GUI/Gtk.php create mode 100644 src/tools/pear/src/PHPUnit/GUI/HTML.php create mode 100644 src/tools/pear/src/PHPUnit/GUI/HTML.tpl create mode 100644 src/tools/pear/src/PHPUnit/GUI/SetupDecorator.php create mode 100644 src/tools/pear/src/PHPUnit/RepeatedTest.php create mode 100644 src/tools/pear/src/PHPUnit/Skeleton.php create mode 100644 src/tools/pear/src/PHPUnit/TestCase.php create mode 100644 src/tools/pear/src/PHPUnit/TestDecorator.php create mode 100644 src/tools/pear/src/PHPUnit/TestFailure.php create mode 100644 src/tools/pear/src/PHPUnit/TestListener.php create mode 100644 src/tools/pear/src/PHPUnit/TestResult.php create mode 100644 src/tools/pear/src/PHPUnit/TestSuite.php diff --git a/bin/upgrade-1.3-to-1.4.sql b/bin/upgrade-1.3-to-1.4.sql index 8041cba33..39cea5b36 100644 --- a/bin/upgrade-1.3-to-1.4.sql +++ b/bin/upgrade-1.3-to-1.4.sql @@ -25,3 +25,36 @@ DROP TABLE as_cmemb CASCADE; DROP SEQUENCE as_struct_id_seq_seq; DROP SEQUENCE as_tree_id_seq_seq; +ALTER TABLE cc_files + ADD COLUMN track_title character varying(512); +ALTER TABLE cc_files + ADD COLUMN artist_name character varying(512); +ALTER TABLE cc_files + ADD COLUMN bit_rate character varying(32); +ALTER TABLE cc_files + ADD COLUMN sample_rate character varying(32); +ALTER TABLE cc_files + ADD COLUMN format character varying(128); +ALTER TABLE cc_files + ADD COLUMN length character (16); +ALTER TABLE cc_files + ADD COLUMN album_title character varying(512); +ALTER TABLE cc_files + ADD COLUMN genre character varying(64); +ALTER TABLE cc_files + ADD COLUMN comments text; +ALTER TABLE cc_files + ADD COLUMN "year" character varying(16); +ALTER TABLE cc_files + ADD COLUMN track_number integer; +ALTER TABLE cc_files + ADD COLUMN channels integer; +ALTER TABLE cc_files + ADD COLUMN url character varying(1024); + + + + + + + \ No newline at end of file diff --git a/src/modules/alib/var/Alib.php b/src/modules/alib/var/Alib.php index 3bbb65921..8fa7c51a9 100644 --- a/src/modules/alib/var/Alib.php +++ b/src/modules/alib/var/Alib.php @@ -128,7 +128,7 @@ class Alib { public static function AddPerm($sid, $action, $oid, $type='A') { global $CC_CONFIG, $CC_DBC; - $permid = $CC_DBC->nextId($CC_CONFIG['permTable']."_id_seq"); + $permid = $CC_DBC->nextId($CC_CONFIG['permSequence']); $sql = "INSERT INTO ".$CC_CONFIG['permTable']." (permid, subj, action, obj, type)" ." VALUES ($permid, $sid, '$action', $oid, '$type')"; $r = $CC_DBC->query($sql); diff --git a/src/modules/alib/var/Subjects.php b/src/modules/alib/var/Subjects.php index 431e70d20..e13169c29 100644 --- a/src/modules/alib/var/Subjects.php +++ b/src/modules/alib/var/Subjects.php @@ -37,7 +37,7 @@ class Subjects { if (!$p_login) { return $CC_DBC->raiseError("Subjects::AddSubj: empty login"); } - $id = $CC_DBC->nextId($CC_CONFIG['subjTable']."_id_seq"); + $id = $CC_DBC->nextId($CC_CONFIG['subjSequence']); if (PEAR::isError($id)) { return $id; } @@ -441,7 +441,7 @@ class Subjects { } } } else { - $id = $CC_DBC->nextId($CC_CONFIG['smembTable']."_id_seq"); + $id = $CC_DBC->nextId($CC_CONFIG['smembSequence']); if (PEAR::isError($id)) { return $id; } diff --git a/src/modules/storageServer/var/BasicStor.php b/src/modules/storageServer/var/BasicStor.php index 5d3e473f5..9dd0d612e 100644 --- a/src/modules/storageServer/var/BasicStor.php +++ b/src/modules/storageServer/var/BasicStor.php @@ -20,6 +20,22 @@ require_once(dirname(__FILE__)."/../../alib/var/Alib.php"); require_once("StoredFile.php"); require_once("Transport.php"); +$g_metadata_xml_to_db_mapping = array( + 'dc:format' => "format", + "ls:bitrate" => "bit_rate", + "ls:samplerate" => "sample_rate", + "dcterms:extent" => "length", + "dc:title" => "track_title", + "dc:description" => "comments", + "dc:type" => "genre", + "dc:creator" => "artist_name", + "dc:source" => "album_title", + "ls:channels" => "channels", + "ls:filename" => "name", + "ls:year" => "year", + "ls:url" => "url", + "ls:track_num" => "track_number"); + /** * Core of Campcaster file storage module * @@ -683,10 +699,11 @@ class BasicStor { if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } - $r = $storedFile->md->getMetadataValue('dc:title', $lang, $deflang); - if (PEAR::isError($r)) { - return $r; - } +// $r = $storedFile->md->getMetadataValue('dc:title', $lang, $deflang); +// if (PEAR::isError($r)) { +// return $r; +// } + $r = $storedFile->md["title"]; $title = (isset($r[0]['value']) ? $r[0]['value'] : 'unknown'); return $title; } @@ -741,24 +758,42 @@ class BasicStor { return $storedFile; } if (is_null($category)) { - return $storedFile->md->getAllMetadata(); + return $storedFile->md; } elseif (is_array($category)) { - $values = array(); - foreach ($category as $tmpCat) { - $values[$tmpCat] = $storedFile->md->getMetadataValue($tmpCat); - } - return $values; + $values = array(); + foreach ($category as $tmpCat) { +// $values[$tmpCat] = $storedFile->md->getMetadataValue($tmpCat); + $values[$tmpCat] = $storedFile->md[$tmpCat]; + } + return $values; } else { - return $storedFile->md->getMetadataValue($category); +// return $storedFile->md->getMetadataValue($category); + return $storedFile->md[$category]; } } + public static function xmlCategoryToDbColumn($p_category) + { + global $g_metadata_xml_to_db_mapping; + if (array_key_exists($p_category, $g_metadata_xml_to_db_mapping)) { + return $g_metadata_xml_to_db_mapping[$p_category]; + } + return null; + } + + + public static function dbColumnToXmlCatagory($p_dbColumn) + { + global $g_metadata_xml_to_db_mapping; + return array_search($p_dbColumn, $g_metadata_xml_to_db_mapping); + } + /** * Set metadata element value * * @param int|StoredFile $id - * Virtual file's local id + * Database ID of file * @param string $category * Metadata element identification (e.g. dc:title) * @param string $value @@ -773,34 +808,45 @@ class BasicStor { * flag, if true, regenerate XML file * @return boolean */ - public function bsSetMetadataValue($id, $category, $value, - $lang=NULL, $mid=NULL, $container='metadata', $regen=TRUE) + public static function bsSetMetadataValue($p_id, $p_category, $p_value)/*, + $lang=NULL, $mid=NULL, $container='metadata', $regen=TRUE)*/ { - if (!is_string($category) || is_array($value)) { + global $CC_CONFIG, $CC_DBC; + if (!is_string($p_category) || is_array($p_value)) { return FALSE; } - if (is_a($id, "StoredFile")) { - $storedFile =& $id; + if (is_a($p_id, "StoredFile")) { + $storedFile =& $p_id; } else { - $storedFile = StoredFile::Recall($id); + $storedFile = StoredFile::Recall($p_id); if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } } - if ($category == 'dcterms:extent') { - $value = BasicStor::NormalizeExtent($value); + if ($p_category == 'dcterms:extent') { + $p_value = BasicStor::NormalizeExtent($p_value); } - $res = $storedFile->md->setMetadataValue($category, $value, $lang, $mid, $container); - if (PEAR::isError($res)) { - return $res; - } - if ($regen) { - $r = $storedFile->md->regenerateXmlFile(); - if (PEAR::isError($r)) { - return $r; + $columnName = BasicStor::xmlCategoryToDbColumn($p_category); // Get column name + + if (!is_null($columnName)) { + $escapedValue = pg_escape_string($p_value); + $sql = "UPDATE ".$CC_CONFIG["filesTable"] + ." SET $columnName='$escapedValue'" + ." WHERE id=".$storedFile->getId(); + //var_dump($sql); + //$res = $storedFile->md->setMetadataValue($category, $value, $lang, $mid, $container); + $res = $CC_DBC->query($sql); + if (PEAR::isError($res)) { + return $res; } } - return $res; +// if ($regen) { +// $r = $storedFile->md->regenerateXmlFile(); +// if (PEAR::isError($r)) { +// return $r; +// } +// } +// return $res; } @@ -826,8 +872,8 @@ class BasicStor { /** * Set metadata values in 'batch' mode * - * @param int $id - * Virtual file's local ID + * @param int|StoredFile $id + * Database ID of file or StoredFile object * @param array $values * array of key/value pairs * (e.g. 'dc:title'=>'New title') @@ -839,33 +885,37 @@ class BasicStor { * flag, if true, regenerate XML file * @return boolean */ - public function bsSetMetadataBatch( + public static function bsSetMetadataBatch( $id, $values, $lang=NULL, $container='metadata', $regen=TRUE) { if (!is_array($values)) { $values = array($values); } - $storedFile = StoredFile::Recall($id); - if (is_null($storedFile) || PEAR::isError($storedFile)) { - return $storedFile; - } - foreach ($values as $category => $oneValue) { - $res = $this->bsSetMetadataValue($storedFile, $category, - $oneValue, $lang, NULL, $container, FALSE); - if (PEAR::isError($res)) { - return $res; - } - } - if ($regen) { + if (is_a($id, "StoredFile")) { + $storedFile =& $id; + } else { $storedFile = StoredFile::Recall($id); if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } - $r = $storedFile->md->regenerateXmlFile(); - if (PEAR::isError($r)) { - return $r; + } + foreach ($values as $category => $oneValue) { + $res = BasicStor::bsSetMetadataValue($storedFile, $category, + $oneValue/*, $lang, NULL, $container, FALSE*/); + if (PEAR::isError($res)) { + return $res; } } +// if ($regen) { +// $storedFile = StoredFile::Recall($id); +// if (is_null($storedFile) || PEAR::isError($storedFile)) { +// return $storedFile; +// } +// $r = $storedFile->md->regenerateXmlFile(); +// if (PEAR::isError($r)) { +// return $r; +// } +// } return TRUE; } @@ -1015,7 +1065,8 @@ class BasicStor { if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } - $MDfname = $storedFile->md->getFileName(); +// $MDfname = $storedFile->md->getFileName(); + $MDfname = $storedFile->md["name"]; if (PEAR::isError($MDfname)) { return $MDfname; } @@ -1032,7 +1083,7 @@ class BasicStor { $string = $r = $storedFile->outputToM3u(); break; default: - $string = $r = $storedFile->md->genXmlDoc(); +// $string = $r = $storedFile->md->genXmlDoc(); } if (PEAR::isError($r)) { return $r; diff --git a/src/modules/storageServer/var/DataEngine.php b/src/modules/storageServer/var/DataEngine.php index 8619af751..63342a8cb 100644 --- a/src/modules/storageServer/var/DataEngine.php +++ b/src/modules/storageServer/var/DataEngine.php @@ -401,37 +401,43 @@ class DataEngine { // Each metadata value is LEFT JOINED to the results, and has the // name of its qualified name with ":" replaced with "_". // Here we also make the ORDER BY clause. - $metadataJoinSql = array(); +// $metadataJoinSql = array(); $orderBySql = array(); // $dataName contains the names of the metadata columns we want to // fetch. It is indexed numerically starting from 1, and the value // in the array is the qualified name with ":" replaced with "_". // e.g. "dc:creator" becomes "dc_creator". - $dataName = array(); - foreach ($metadataNames as $j => $qname) { - $i = $j + 1; - $obSplitQn = XML_Util::splitQualifiedName($qname); - $obNs = $obSplitQn['namespace']; - $obLp = $obSplitQn['localPart']; - $desc = (isset($descA[$j]) ? $descA[$j] : NULL); - $retype = ($obLp == 'mtime' ? '::timestamp with time zone' : '' ); - $metadataJoinSql[] = - "LEFT JOIN ".$CC_CONFIG['mdataTable']." m$i\n". - " ON m$i.gunid = sq2.gunid AND m$i.predicate='$obLp'". - " AND m$i.objns='_L' AND m$i.predxml='T'". - (!is_null($obNs)? " AND m$i.predns='$obNs'":''); +// $dataName = array(); +// foreach ($metadataNames as $j => $qname) { +// $i = $j + 1; +// $obSplitQn = XML_Util::splitQualifiedName($qname); +// $obNs = $obSplitQn['namespace']; +// $obLp = $obSplitQn['localPart']; +// $desc = (isset($descA[$j]) ? $descA[$j] : NULL); +// $retype = ($obLp == 'mtime' ? '::timestamp with time zone' : '' ); +// $metadataJoinSql[] = +// "LEFT JOIN ".$CC_CONFIG['mdataTable']." m$i\n". +// " ON m$i.gunid = sq2.gunid AND m$i.predicate='$obLp'". +// " AND m$i.objns='_L' AND m$i.predxml='T'". +// (!is_null($obNs)? " AND m$i.predns='$obNs'":''); +// +// $dataName[$qname] = str_replace(":", "_", $qname); +// if (in_array($qname, $orderbyQns)) { +// $orderBySql[] = $dataName[$qname].$retype.($desc? ' DESC':''); +// } +// } - $dataName[$qname] = str_replace(":", "_", $qname); - if (in_array($qname, $orderbyQns)) { - $orderBySql[] = $dataName[$qname].$retype.($desc? ' DESC':''); - } + foreach ($orderbyQns as $xmlTag) { + $columnName = BasicStor::xmlCategoryToDbColumn($xmlTag); + $orderBySql[] = $columnName; } - if (!$orderby) { - $fldsPart = "DISTINCT to_hex(f.gunid)as gunid, f.ftype, f.id "; - } else { - $fldsPart = "DISTINCT f.gunid, f.ftype, f.id "; - } +// if (!$orderby) { +// $fldsPart = "DISTINCT to_hex(f.gunid)as gunid, f.ftype, f.id "; +// } else { +// $fldsPart = "DISTINCT f.gunid, f.ftype, f.id "; +// } + $fldsPart = " * "; $fileCond = "(f.state='ready' OR f.state='edited')"; if (!is_null($filetype)) { @@ -442,31 +448,33 @@ class DataEngine { } else { $sql = $this->_makeOrSql($fldsPart, $whereArr, $fileCond, false); } - + // the actual values to fetch if ($orderby) { - $tmpSql = "SELECT to_hex(sq2.gunid)as gunid, sq2.ftype, sq2.id"; - $i = 1; - foreach ($metadataNames as $qname) { - // Special case for track number because if we use text - // sorting of this value, then 10 comes right after 1. - // So we convert track number to an integer for ordering. + //$tmpSql = "SELECT to_hex(sq2.gunid)as gunid, sq2.ftype, sq2.id"; + $tmpSql = "SELECT * "; +// $i = 1; +// foreach ($metadataNames as $qname) { +// // Special case for track number because if we use text +// // sorting of this value, then 10 comes right after 1. +// // So we convert track number to an integer for ordering. +// +// // PaulB: see my note above about why this is commented out. +// //if ($qname == "ls:track_num") { +// // $tmpSql .= ", CAST(m$i.object as integer) as ls_track_num"; +// //} else { +//// $tmpSql .= ", m$i.object as ".$dataName[$qname]; +// $tmpSql .= ", m$i.object as ".$dataName[$qname]; +// //} +// $i++; +// } - // PaulB: see my note above about why this is commented out. - //if ($qname == "ls:track_num") { - // $tmpSql .= ", CAST(m$i.object as integer) as ls_track_num"; - //} else { - $tmpSql .= ", m$i.object as ".$dataName[$qname]; - //} - $i++; - } - - $tmpSql .= "\nFROM (\n$sql\n)sq2\n". - join("\n", $metadataJoinSql). + $tmpSql .= "\nFROM \n".$CC_CONFIG["filesTable"]."\n". "ORDER BY ".join(",", $orderBySql)."\n"; $sql = $tmpSql; } - + + $_SESSION["debug"] = $tmpSql; // Get the number of results $cnt = $this->_getNumRows($sql); if (PEAR::isError($cnt)) { @@ -490,13 +498,24 @@ class DataEngine { 'id' => $it['id'], 'gunid' => $gunid, 'type' => strtolower($it['ftype']), - 'title' => $it['dc_title'], - 'creator' => $it['dc_creator'], - 'duration' => $it['dcterms_extent'], - 'length' => $it['dcterms_extent'], - 'source' => $it['dc_source'], - 'track_num' => $it['ls_track_num'], + 'title' => $it['track_title'], + 'creator' => $it['artist_name'], + 'duration' => $it['length'], + 'length' => $it['length'], + 'source' => $it['album_title'], + 'track_num' => $it['track_number'], ); +// $eres[] = array( +// 'id' => $it['id'], +// 'gunid' => $gunid, +// 'type' => strtolower($it['ftype']), +// 'title' => $it['dc_title'], +// 'creator' => $it['dc_creator'], +// 'duration' => $it['dcterms_extent'], +// 'length' => $it['dcterms_extent'], +// 'source' => $it['dc_source'], +// 'track_num' => $it['ls_track_num'], +// ); } return array('results'=>$eres, 'cnt'=>$cnt); } diff --git a/src/modules/storageServer/var/GreenBox.php b/src/modules/storageServer/var/GreenBox.php index 60a4e682e..10e1dfff9 100644 --- a/src/modules/storageServer/var/GreenBox.php +++ b/src/modules/storageServer/var/GreenBox.php @@ -1,10 +1,10 @@ "; } require_once("LocStor.php"); -if ($WHITE_SCREEN_OF_DEATH) { +if (isset($WHITE_SCREEN_OF_DEATH) && $WHITE_SCREEN_OF_DEATH) { echo __FILE__.':line '.__LINE__.": Loaded LocStor
"; } require_once('Prefs.php'); @@ -282,7 +282,9 @@ class GreenBox extends BasicStor { if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } - $arr = $storedFile->md->genPhpArray(); + return $storedFile->md; + +// $arr = $storedFile->md->genPhpArray(); $md = FALSE; foreach ($arr['children'] as $i=>$a) { if ($a['elementname'] == 'metadata'){ @@ -365,7 +367,7 @@ class GreenBox extends BasicStor { if (($res = BasicStor::Authorize('write', $id, $sessid)) !== TRUE) { return $res; } - return $this->bsSetMetadataValue($id, $category, $value, $lang, $mid); + return $this->bsSetMetadataValue($id, $category, $value /*, $lang, $mid*/); } // fn setMetadataValue @@ -565,10 +567,10 @@ class GreenBox extends BasicStor { if (is_null($storedFile) || PEAR::isError($storedFile)) { return $storedFile; } - $r = $storedFile->md->regenerateXmlFile(); - if (PEAR::isError($r)) { - return $r; - } +// $r = $storedFile->md->regenerateXmlFile(); +// if (PEAR::isError($r)) { +// return $r; +// } $this->setEditFlag($gunid, FALSE, $sessid); return $gunid; } // fn releaseLockedPlaylist diff --git a/src/modules/storageServer/var/LocStor.php b/src/modules/storageServer/var/LocStor.php index 49c41ec54..0a0a35634 100644 --- a/src/modules/storageServer/var/LocStor.php +++ b/src/modules/storageServer/var/LocStor.php @@ -1,10 +1,10 @@ "; } require_once("Transport.php"); -if ($WHITE_SCREEN_OF_DEATH) { +if (isset($WHITE_SCREEN_OF_DEATH) && $WHITE_SCREEN_OF_DEATH) { echo __FILE__.':line '.__LINE__.": Loaded Transport
"; } @@ -196,7 +196,7 @@ class LocStor extends BasicStor { } $oid = $storedFile->getId(); $r = $this-> bsSetMetadataValue( - $oid, 'ls:url', $url, NULL, NULL, 'metadata'); + $oid, 'ls:url', $url /*, NULL, NULL, 'metadata'*/); if (PEAR::isError($r)) { return $r; } diff --git a/src/modules/storageServer/var/MetaData.php b/src/modules/storageServer/var/MetaData.php index ad211bc2d..628d9d8ef 100644 --- a/src/modules/storageServer/var/MetaData.php +++ b/src/modules/storageServer/var/MetaData.php @@ -49,7 +49,7 @@ class MetaData { /** * @var array */ - private $metadata; + private $metadata; /** @@ -278,30 +278,13 @@ class MetaData { public function setMetadataElement($p_id, $p_value=NULL) { global $CC_CONFIG, $CC_DBC; - $info = $CC_DBC->getRow(" - SELECT parmd.predns as parns, parmd.predicate as parname, - md.predxml, md.predns as chns, md.predicate as chname - FROM ".$CC_CONFIG['mdataTable']." parmd - INNER JOIN ".$CC_CONFIG['mdataTable']." md - ON parmd.id=md.subject::integer AND md.subjns='_I' - WHERE md.id=$p_id"); - if (PEAR::isError($info)) { - return $info; - } - if (is_null($info)) { - return PEAR::raiseError( - "MetaData::setMetadataElement: parent container not found"); - } - extract($info); - $parname = ($parns ? "$parns:" : '').$parname; - $category = ($chns ? "$chns:" : '').$chname; - $r = $this->validateOneValue($parname, $category, $predxml, $p_value); - if (PEAR::isError($r)) { - return $r; - } +// $r = $this->validateOneValue($parname, $category, $predxml, $p_value); +// if (PEAR::isError($r)) { +// return $r; +// } if (!is_null($p_value)) { $escapedValue = pg_escape_string($p_value); - $sql = "UPDATE ".$CC_CONFIG['mdataTable']." + $sql = "UPDATE ".$CC_CONFIG['filesTable']." SET object='$escapedValue', objns='_L' WHERE id={$p_id}"; $res = $CC_DBC->query($sql); @@ -523,6 +506,7 @@ class MetaData { } $parid = $contArr[0]['mid']; if (is_null($parid)) { + //var_dump($contArr); return PEAR::raiseError( "MetaData::setMetadataValue: container ($p_container) not found" ); @@ -746,7 +730,6 @@ class MetaData { */ private function storeNode(&$node, $parid=NULL, $nSpaces=array()) { - //echo $node->node_name().", ".$node->node_type().", ".$node->prefix().", $parid.\n"; $nSpaces = array_merge($nSpaces, $node->nSpaces); // null parid = root node of metadata tree $subjns = (is_null($parid)? '_G' : '_I'); @@ -758,12 +741,10 @@ class MetaData { } else { $objns = '_L'; } - $id = $this->storeRecord($subjns, $subject, - $node->ns, $node->name, 'T', $objns, $object); + $id = $this->storeRecord($subjns, $subject, $node->ns, $node->name, 'T', $objns, $object); // process attributes foreach ($node->attrs as $atn => $ato) { - $this->storeRecord('_I', $id, - $ato->ns, $ato->name, 'A', '_L', $ato->val); + $this->storeRecord('_I', $id, $ato->ns, $ato->name, 'A', '_L', $ato->val); } // process child nodes foreach ($node->children as $ch) { @@ -771,8 +752,7 @@ class MetaData { } // process namespace definitions foreach ($node->nSpaces as $ns => $uri) { - $this->storeRecord('_I', $id, - 'xmlns', $ns, 'N', '_L', $uri); + $this->storeRecord('_I', $id, 'xmlns', $ns, 'N', '_L', $uri); } return $id; } @@ -841,7 +821,7 @@ class MetaData { $predicate_sql = is_null($predicate) ? "NULL" : "'".pg_escape_string($predicate)."'"; $objns_sql = is_null($objns) ? "NULL" : "'".pg_escape_string($objns)."'"; $object_sql = is_null($object) ? "NULL" : "'".pg_escape_string($object)."'"; - $id = $CC_DBC->nextId($CC_CONFIG['mdataTable']."_id_seq"); + $id = $CC_DBC->nextId($CC_CONFIG['mdataSequence']); if (PEAR::isError($id)) { return $id; } @@ -851,7 +831,7 @@ class MetaData { predns, predicate, predxml, objns, object) VALUES - ($id, x'{$this->gunid}'::bigint, $subjns_sql, $subject_sql, + (DEFAULT, x'{$this->gunid}'::bigint, $subjns_sql, $subject_sql, $predns_sql, $predicate_sql, '$predxml', $objns_sql, $object_sql )"); diff --git a/src/modules/storageServer/var/Prefs.php b/src/modules/storageServer/var/Prefs.php index 7c9039510..49f0dc6c9 100644 --- a/src/modules/storageServer/var/Prefs.php +++ b/src/modules/storageServer/var/Prefs.php @@ -285,7 +285,7 @@ class Prefs { public static function Insert($subjid, $keystr, $valstr='') { global $CC_CONFIG, $CC_DBC; - $id = $CC_DBC->nextId($CC_CONFIG['prefTable']."_id_seq"); + $id = $CC_DBC->nextId($CC_CONFIG['prefSequence']); if (PEAR::isError($id)) { return $id; } diff --git a/src/modules/storageServer/var/StoredFile.php b/src/modules/storageServer/var/StoredFile.php index a2ee340ea..900390213 100644 --- a/src/modules/storageServer/var/StoredFile.php +++ b/src/modules/storageServer/var/StoredFile.php @@ -1,5 +1,5 @@ resDir = $this->_getResDir($this->gunid); $this->filepath = "{$this->resDir}/{$this->gunid}"; $this->exists = is_file($this->filepath) && is_readable($this->filepath); - $this->md = new MetaData($this->gunid, $this->resDir); + $this->md = $this->loadMetadata(); } + public function loadMetadata() + { + global $CC_CONFIG, $CC_DBC; + $escapedValue = pg_escape_string($this->gunid); + $sql = "SELECT * FROM ".$CC_CONFIG["filesTable"] + ." WHERE gunid=x'$escapedValue'::bigint"; + //var_dump($sql); + $this->md = $CC_DBC->getRow($sql); + if (PEAR::isError($this->md)) { + $error = $this->md; + $this->md = null; + return $error; + } + if (is_null($this->md)) { + $this->md = array(); + return; + } + $compatibilityData = array(); + foreach ($this->md as $key => $value) { + if ($xmlName = BasicStor::dbColumnToXmlCatagory($key)) { + $compatibilityData[$xmlName] = $value; + } + } + $this->md = array_merge($this->md, $compatibilityData); + //$_SESSION["debug"] = $this->md; + } + + public function setFormat($p_value) + { + $this->md["format"] = $p_value; + } + + public function replaceMetadata($p_values) + { + global $CC_CONFIG, $CC_DBC; + foreach ($p_values as $category => $value) { + $escapedValue = pg_escape_string($value); + $columnName = BasicStor::xmlCategoryToDbColumn($category); + if (!is_null($columnName)) { + $sql = "UPDATE ".$CC_CONFIG["filesTable"] + ." SET $columnName='$escapedValue'" + ." WHERE gunid = '".$this->gunid."'"; + $CC_DBC->query($sql); + } + } + $this->loadMetadata(); + } + + public function clearMetadata() + { + $metadataColumns = array("format", "bit_rate", "sample_rate", "length", + "track_title", "comments", "genre", "artist_name", "channels", "name", + "year", "url", "track_number"); + foreach ($metadataColumns as $columnName) { + if (!is_null($columnName)) { + $sql = "UPDATE ".$CC_CONFIG["filesTable"] + ." SET $columnName=''" + ." WHERE gunid = '".$this->gunid."'"; + $CC_DBC->query($sql); + } + } + } /* ========= 'factory' methods - should be called to construct StoredFile */ /** @@ -458,29 +520,31 @@ class StoredFile { if (!is_integer($storedFile->id)) { // NOTE: POSTGRES-SPECIFIC - $sql = "SELECT currval('".$CC_CONFIG["filesSequence"]."')"; + $sql = "SELECT currval('".$CC_CONFIG["filesSequence"]."_seq')"; $storedFile->id = $CC_DBC->getOne($sql); } // Insert metadata $metadata = $p_values['metadata']; + BasicStor::bsSetMetadataBatch($storedFile->id, $metadata); + // $mdataLoc = ($metadata[0]=="/")? "file":"string"; // for non-absolute paths: - $mdataLoc = ($metadata[0]!="<")? "file":"string"; - if (is_null($metadata) || ($metadata == '') ) { - $metadata = dirname(__FILE__).'/emptyMdata.xml'; - $mdataLoc = 'file'; - } else { - $emptyState = FALSE; - } - if ( ($mdataLoc == 'file') && !file_exists($metadata)) { - return PEAR::raiseError("StoredFile::Insert: ". - "metadata file not found ($metadata)"); - } - $res = $storedFile->md->insert($metadata, $mdataLoc, $storedFile->ftype); - if (PEAR::isError($res)) { - $CC_DBC->query("ROLLBACK"); - return $res; - } +// $mdataLoc = ($metadata[0]!="<")? "file":"string"; +// if (is_null($metadata) || ($metadata == '') ) { +// $metadata = dirname(__FILE__).'/emptyMdata.xml'; +// $mdataLoc = 'file'; +// } else { +// $emptyState = FALSE; +// } +// if ( ($mdataLoc == 'file') && !file_exists($metadata)) { +// return PEAR::raiseError("StoredFile::Insert: ". +// "metadata file not found ($metadata)"); +// } +// $res = $storedFile->md->insert($metadata, $mdataLoc, $storedFile->ftype); +// if (PEAR::isError($res)) { +// $CC_DBC->query("ROLLBACK"); +// return $res; +// } // Save media file if (!empty($p_values['filepath'])) { @@ -567,7 +631,8 @@ class StoredFile { $storedFile = new StoredFile($gunid); } $storedFile->gunidBigint = $row['gunid_bigint']; - $storedFile->md->gunidBigint = $row['gunid_bigint']; + //$storedFile->md->gunidBigint = $row['gunid_bigint']; + $storedFile->md["gunid"] = $row['gunid_bigint']; $storedFile->id = $row['id']; $storedFile->name = $row['name']; $storedFile->mime = $row['mime']; @@ -578,7 +643,7 @@ class StoredFile { $storedFile->mtime = $row['mtime']; $storedFile->md5 = $row['md5']; $storedFile->exists = TRUE; - $storedFile->md->setFormat($row['ftype']); + $storedFile->setFormat($row['ftype']); return $storedFile; } @@ -772,7 +837,7 @@ class StoredFile { if (PEAR::isError($storedFile)) { return $storedFile; } - $storedFile->md->replace($p_src->md->getMetadata(), 'string'); + $storedFile->replaceMetadata($p_src->getAllMetadata(), 'string'); return $storedFile; } @@ -814,7 +879,8 @@ class StoredFile { if ($p_metadata != '') { $res = $this->setMetadata($p_metadata, $p_mdataLoc); } else { - $res = $this->md->delete(); +// $res = $this->md->delete(); + $res = $this->clearMetadata(); } if (PEAR::isError($res)) { $CC_DBC->query("ROLLBACK"); @@ -888,10 +954,10 @@ class StoredFile { return $res; } } - $r = $this->md->regenerateXmlFile(); - if (PEAR::isError($r)) { - return $r; - } +// $r = $this->md->regenerateXmlFile(); +// if (PEAR::isError($r)) { +// return $r; +// } return TRUE; } @@ -918,11 +984,11 @@ class StoredFile { $CC_DBC->query("ROLLBACK"); return $res; } - $r = $this->md->regenerateXmlFile(); - if (PEAR::isError($r)) { - $CC_DBC->query("ROLLBACK"); - return $r; - } +// $r = $this->md->regenerateXmlFile(); +// if (PEAR::isError($r)) { +// $CC_DBC->query("ROLLBACK"); +// return $r; +// } $res = $CC_DBC->query("COMMIT"); if (PEAR::isError($res)) { return $res; @@ -939,7 +1005,8 @@ class StoredFile { */ public function getMetadata() { - return $this->md->getMetadata(); + //return $this->md->getMetadata(); + return $this->md; } @@ -1056,10 +1123,10 @@ class StoredFile { return $res; } } - $res = $this->md->delete(); - if (PEAR::isError($res)) { - return $res; - } +// $res = $this->md->delete(); +// if (PEAR::isError($res)) { +// return $res; +// } $sql = "SELECT to_hex(token)as token, ext " ." FROM ".$CC_CONFIG['accessTable'] ." WHERE gunid=x'{$this->gunid}'::bigint"; @@ -1370,7 +1437,8 @@ class StoredFile { */ public function getRealMetadataFileName() { - return $this->md->getFileName(); + //return $this->md->getFileName(); + return $this->md["name"]; } diff --git a/src/modules/storageServer/var/Transport.php b/src/modules/storageServer/var/Transport.php index 5ea961d7b..35776f62c 100644 --- a/src/modules/storageServer/var/Transport.php +++ b/src/modules/storageServer/var/Transport.php @@ -34,7 +34,6 @@ include_once("TransportRecord.php"); * @@ -139,7 +138,7 @@ class Transport * @return array * struct/hasharray with fields: * trtype: string - - * audioclip | playlist | playlistPkg | search | metadata | file + * audioclip | playlist | playlistPkg | metadata | file * state: string - transport state * init | pending | waiting | finished | closed | failed * direction: string - up | down @@ -175,11 +174,6 @@ class Transport $res['realsum'] = $check['realsum']; } } - // do not return finished on finished search job upload - // - whole search is NOT finished - if ($res['trtype'] == "searchjob" && $res['direction'] == "up" && $res['state'] == "finished") { - $res['state'] = "waiting"; - } return $res; } @@ -1045,9 +1039,9 @@ class Transport $title = $ret['title']; $pars = array(); switch ($trtype) { - case "searchjob": - $r = $trec->setState('waiting', $pars); - break; +// case "searchjob": +// $r = $trec->setState('waiting', $pars); +// break; case "file": $r = $trec->setState('waiting',array_merge($pars, array( 'trtype'=>$trtype, @@ -1331,20 +1325,20 @@ class Transport return $ret; } - if ($row['trtype'] == 'searchjob') { - @unlink($row['localfile']); - $r = $trec->setState('init', array( - 'direction' => 'down', - 'pdtoken' => $ret['token'], - 'expectedsum' => $ret['chsum'], - 'expectedsize' => $ret['size'], - 'url' => $ret['url'], - 'realsize' => 0, - )); - $this->startCronJobProcess($trec->trtok); - } else { +// if ($row['trtype'] == 'searchjob') { +// @unlink($row['localfile']); +// $r = $trec->setState('init', array( +// 'direction' => 'down', +// 'pdtoken' => $ret['token'], +// 'expectedsum' => $ret['chsum'], +// 'expectedsize' => $ret['size'], +// 'url' => $ret['url'], +// 'realsize' => 0, +// )); +// $this->startCronJobProcess($trec->trtok); +// } else { $r = $trec->close(); - } +// } if (PEAR::isError($r)) { return $r; } @@ -1497,7 +1491,7 @@ class Transport break; case "audioclip": case "metadata": - case "searchjob": +// case "searchjob": case "file": break; default: @@ -1675,7 +1669,6 @@ class Transport $key = 'archiveServerLocation'; $archiveUrl = $pr->loadGroupPref($group, $key, false); - echo "Archive URL: $archiveUrl\n"; if ($archiveUrl) { $archiveUrlInfo = parse_url($archiveUrl); if ($archiveUrlInfo['port']) { @@ -1835,87 +1828,6 @@ class Transport return $CC_DBC->query("DELETE FROM ".$CC_CONFIG['transTable']); } - - /** - * Install method
- * - * direction: up | down - * state: init | pending | waiting | finished | closed | failed | paused - * trtype: audioclip | playlist | playlistPkg | searchjob | metadata | file - * - */ -// function install() -// { -// global $CC_CONFIG, $CC_DBC; -// $r = $CC_DBC->query("CREATE TABLE {$this->transTable} ( -// id int not null, -- primary key -// trtok char(16) not null, -- transport token -// direction varchar(128) not null, -- direction: up|down -// state varchar(128) not null, -- state -// trtype varchar(128) not null, -- transport type -// lock char(1) not null default 'N',-- running lock -// target varchar(255) default NULL, -- target system, -// -- if NULL => predefined set -// rtrtok char(16) default NULL, -- remote hub's transport token -// mdtrtok char(16), -- metadata transport token -// gunid bigint, -- global unique id -// pdtoken bigint, -- put/download token from archive -// url varchar(255), -- url on remote side -// localfile varchar(255), -- pathname of local part -// fname varchar(255), -- mnemonic filename -// title varchar(255), -- dc:title mdata value (or filename ...) -// expectedsum char(32), -- expected file checksum -// realsum char(32), -- checksum of transported part -// expectedsize int, -- expected filesize in bytes -// realsize int, -- filesize of transported part -// uid int, -- local user id of transport owner -// errmsg varchar(255), -- error message string for failed tr. -// start timestamp, -- starttime -// ts timestamp -- mtime -// )"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->createSequence("{$this->transTable}_id_seq"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->query("CREATE UNIQUE INDEX {$this->transTable}_id_idx -// ON {$this->transTable} (id)"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->query("CREATE UNIQUE INDEX {$this->transTable}_trtok_idx -// ON {$this->transTable} (trtok)"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->query("CREATE UNIQUE INDEX {$this->transTable}_token_idx -// ON {$this->transTable} (pdtoken)"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->query("CREATE INDEX {$this->transTable}_gunid_idx -// ON {$this->transTable} (gunid)"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// $r = $CC_DBC->query("CREATE INDEX {$this->transTable}_state_idx -// ON {$this->transTable} (state)"); -// if (PEAR::isError($r)) { -// echo $r->getMessage()." ".$r->getUserInfo(); -// } -// } - - /** - * Uninstall method - */ -// function uninstall() -// { -// global $CC_CONFIG, $CC_DBC; -// $CC_DBC->query("DROP TABLE {$this->transTable}"); -// $CC_DBC->dropSequence("{$this->transTable}_id_seq"); -// } } ?> \ No newline at end of file diff --git a/src/modules/storageServer/var/TransportRecord.php b/src/modules/storageServer/var/TransportRecord.php index 942d38f41..9a491e7eb 100644 --- a/src/modules/storageServer/var/TransportRecord.php +++ b/src/modules/storageServer/var/TransportRecord.php @@ -80,7 +80,7 @@ class TransportRecord return $defaults['title']; } } - $id = $CC_DBC->nextId($CC_CONFIG['transTable']."_id_seq"); + $id = $CC_DBC->nextId($CC_CONFIG['transSequence']); $names = "id, trtok, direction, state, trtype, start, ts"; $values = "$id, '$trtok', '$direction', 'init', '$trtype', now(), now()"; foreach ($defaults as $k => $v) { diff --git a/src/modules/storageServer/var/conf.php b/src/modules/storageServer/var/conf.php index b17e648af..8fee80e90 100644 --- a/src/modules/storageServer/var/conf.php +++ b/src/modules/storageServer/var/conf.php @@ -126,7 +126,14 @@ $CC_CONFIG['prefTable'] = $CC_CONFIG['tblNamePrefix'].'pref'; $CC_CONFIG['playlogTable'] = $CC_CONFIG['tblNamePrefix'].'playlog'; $CC_CONFIG['scheduleTable'] = $CC_CONFIG['tblNamePrefix'].'schedule'; $CC_CONFIG['backupTable'] = $CC_CONFIG['tblNamePrefix'].'backup'; -$CC_CONFIG['filesSequence'] = $CC_CONFIG['tblNamePrefix']."file_id_seq"; + +$CC_CONFIG['filesSequence'] = $CC_CONFIG['filesTable'].'_id'; +$CC_CONFIG['transSequence'] = $CC_CONFIG['transTable'].'_id'; +$CC_CONFIG['prefSequence'] = $CC_CONFIG['prefTable'].'_id'; +$CC_CONFIG['permSequence'] = $CC_CONFIG['permTable'].'_id'; +$CC_CONFIG['subjSequence'] = $CC_CONFIG['subjTable'].'_id'; +$CC_CONFIG['smembSequence'] = $CC_CONFIG['smembTable'].'_id'; +$CC_CONFIG['mdataSequence'] = $CC_CONFIG['mdataTable'].'_id'; $CC_CONFIG['sysSubjs'] = array( 'root', /*$CC_CONFIG['AdminsGr'],*/ /*$CC_CONFIG['AllGr'],*/ $CC_CONFIG['StationPrefsGr'] diff --git a/src/modules/storageServer/var/install/install.php b/src/modules/storageServer/var/install/install.php index d17674204..dd7cee3d3 100644 --- a/src/modules/storageServer/var/install/install.php +++ b/src/modules/storageServer/var/install/install.php @@ -7,8 +7,6 @@ * */ -$WHITE_SCREEN_OF_DEATH = false; - // Do not allow remote execution $arr = array_diff_assoc($_SERVER, $_ENV); if (isset($arr["DOCUMENT_ROOT"]) && ($arr["DOCUMENT_ROOT"] != "") ) { @@ -22,9 +20,9 @@ echo "*************************\n"; echo "* StorageServer Install *\n"; echo "*************************\n"; -require_once('../conf.php'); -require_once('../GreenBox.php'); -require_once("installInit.php"); +require_once(dirname(__FILE__).'/../conf.php'); +require_once(dirname(__FILE__).'/../GreenBox.php'); +require_once(dirname(__FILE__)."/installInit.php"); campcaster_db_connect(true); //------------------------------------------------------------------------------ @@ -51,7 +49,7 @@ if (!camp_db_table_exists($CC_CONFIG['subjTable'])) { ON ".$CC_CONFIG['subjTable']." (login)"; camp_install_query($sql, false); - $CC_DBC->createSequence($CC_CONFIG['subjTable']."_id_seq"); + $CC_DBC->createSequence($CC_CONFIG['subjSequence']); echo "done.\n"; } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['subjTable']."\n"; @@ -71,7 +69,7 @@ if (!camp_db_table_exists($CC_CONFIG['smembTable'])) { ON ".$CC_CONFIG['smembTable']." (id)"; camp_install_query($sql, false); - $CC_DBC->createSequence($CC_CONFIG['smembTable']."_id_seq"); + //$CC_DBC->createSequence($CC_CONFIG['smembSequence']); echo "done.\n"; } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['smembTable']."\n"; @@ -99,7 +97,7 @@ if (!camp_db_table_exists($CC_CONFIG['permTable'])) { ON ".$CC_CONFIG['permTable']." (subj, action, obj)"; camp_install_query($sql, false); - $CC_DBC->createSequence($CC_CONFIG['permTable']."_id_seq"); + //$CC_DBC->createSequence($CC_CONFIG['permSequence']); echo "done.\n"; } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['permTable']."\n"; @@ -114,9 +112,9 @@ if (!camp_db_table_exists($CC_CONFIG['sessTable'])) { ts timestamp)"; camp_install_query($sql, false); - $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['sessTable']."_sessid_idx - ON ".$CC_CONFIG['sessTable']." (sessid)"; - camp_install_query($sql, false); + // $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['sessTable']."_sessid_idx + // ON ".$CC_CONFIG['sessTable']." (sessid)"; + // camp_install_query($sql, false); $sql = "CREATE INDEX ".$CC_CONFIG['sessTable']."_userid_idx ON ".$CC_CONFIG['sessTable']." (userid)"; @@ -152,23 +150,43 @@ if (!camp_db_table_exists($CC_CONFIG['sessTable'])) { */ if (!camp_db_table_exists($CC_CONFIG['filesTable'])) { echo " * Creating database table ".$CC_CONFIG['filesTable']."..."; - $sql = "CREATE TABLE ".$CC_CONFIG['filesTable']." ( - id int not null, - gunid bigint not null, -- global unique ID - name varchar(255) not null default'', -- human file id ;) - mime varchar(255) not null default'', -- mime type - ftype varchar(128) not null default'', -- file type - state varchar(128) not null default'empty', -- file state - currentlyaccessing int not null default 0, -- access counter - editedby int REFERENCES ".$CC_CONFIG['subjTable'].", -- who edits it - mtime timestamp(6) with time zone, -- lst modif.time - md5 char(32) - )"; + $sql = + "CREATE TABLE ".$CC_CONFIG['filesTable']." + ( + id serial NOT NULL, + gunid bigint NOT NULL, + \"name\" character varying(255) NOT NULL DEFAULT ''::character varying, + mime character varying(255) NOT NULL DEFAULT ''::character varying, + ftype character varying(128) NOT NULL DEFAULT ''::character varying, + state character varying(128) NOT NULL DEFAULT 'empty'::character varying, + currentlyaccessing integer NOT NULL DEFAULT 0, + editedby integer, + mtime timestamp(6) with time zone, + md5 character(32), + track_title character varying(512), + artist_name character varying(512), + bit_rate character varying(32), + sample_rate character varying(32), + format character varying(128), + length character(16), + album_title character varying(512), + genre character varying(64), + comments text, + \"year\" character varying(16), + track_number integer, + channels integer, + url character varying(1024), + CONSTRAINT cc_files_pkey PRIMARY KEY (id), + CONSTRAINT cc_files_editedby_fkey FOREIGN KEY (editedby) + REFERENCES cc_subjs (id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION + )"; + camp_install_query($sql, false); - $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['filesTable']."_id_idx - ON ".$CC_CONFIG['filesTable']." (id)"; - camp_install_query($sql, false); +// $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['filesTable']."_id_idx +// ON ".$CC_CONFIG['filesTable']." (id)"; +// camp_install_query($sql, false); $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['filesTable']."_gunid_idx ON ".$CC_CONFIG['filesTable']." (gunid)"; @@ -182,22 +200,25 @@ if (!camp_db_table_exists($CC_CONFIG['filesTable'])) { ON ".$CC_CONFIG['filesTable']." (md5)"; camp_install_query($sql); + //$CC_DBC->createSequence($CC_CONFIG['filesSequence']); + } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['filesTable']."\n"; } -if (!camp_db_sequence_exists($CC_CONFIG["filesSequence"])) { - echo " * Creating database sequence ".$CC_CONFIG['filesSequence']."..."; - $sql = "CREATE SEQUENCE ".$CC_CONFIG["filesSequence"] - ." INCREMENT 1 - MINVALUE 1 - MAXVALUE 9223372036854775807 - START 1000000 - CACHE 1"; - camp_install_query($sql); -} else { - echo " * Skipping: database sequence already exists: ".$CC_CONFIG['filesSequence']."\n"; -} +//if (!camp_db_sequence_exists($CC_CONFIG["filesSequence"])) { +// echo " * Creating database sequence for ".$CC_CONFIG['filesTable']."...\n"; +// $CC_DBC->createSequence($CC_CONFIG['filesSequence']); +//// $sql = "CREATE SEQUENCE ".$CC_CONFIG["filesSequence"] +//// ." INCREMENT 1 +//// MINVALUE 1 +//// MAXVALUE 9223372036854775807 +//// START 1000000 +//// CACHE 1"; +//// camp_install_query($sql); +//} else { +// echo " * Skipping: database sequence already exists: ".$CC_CONFIG['filesSequence']."\n"; +//} /** * id subjns subject predns predicate objns object @@ -214,9 +235,9 @@ if (!camp_db_sequence_exists($CC_CONFIG["filesSequence"])) { */ if (!camp_db_table_exists($CC_CONFIG['mdataTable'])) { echo " * Creating database table ".$CC_CONFIG['mdataTable']."..."; - $CC_DBC->createSequence($CC_CONFIG['mdataTable']."_id_seq"); + //$CC_DBC->createSequence($CC_CONFIG['mdataSequence']); $sql = "CREATE TABLE ".$CC_CONFIG['mdataTable']." ( - id int not null, + id SERIAL PRIMARY KEY, gunid bigint, subjns varchar(255), -- subject namespace shortcut/uri subject varchar(255) not null default '', @@ -228,9 +249,9 @@ if (!camp_db_table_exists($CC_CONFIG['mdataTable'])) { )"; camp_install_query($sql, false); - $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['mdataTable']."_id_idx - ON ".$CC_CONFIG['mdataTable']." (id)"; - camp_install_query($sql, false); +// $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['mdataTable']."_id_idx +// ON ".$CC_CONFIG['mdataTable']." (id)"; +// camp_install_query($sql, false); $sql = "CREATE INDEX ".$CC_CONFIG['mdataTable']."_gunid_idx ON ".$CC_CONFIG['mdataTable']." (gunid)"; @@ -320,7 +341,7 @@ if (!camp_db_table_exists($CC_CONFIG['transTable'])) { )"; camp_install_query($sql, false); - $CC_DBC->createSequence($CC_CONFIG['transTable']."_id_seq"); + $CC_DBC->createSequence($CC_CONFIG['transSequence']); $sql = "CREATE UNIQUE INDEX ".$CC_CONFIG['transTable']."_id_idx ON ".$CC_CONFIG['transTable']." (id)"; camp_install_query($sql, false); @@ -350,11 +371,11 @@ if (!camp_db_table_exists($CC_CONFIG['transTable'])) { if (!camp_db_table_exists($CC_CONFIG['scheduleTable'])) { echo " * Creating database table ".$CC_CONFIG['scheduleTable']."..."; $sql = "CREATE TABLE ".$CC_CONFIG['scheduleTable']."(" - ." id BIGINT NOT NULL," - ." playlist BIGINT NOT NULL," - ." starts TIMESTAMP NOT NULL," - ." ends TIMESTAMP NOT NULL," - ." PRIMARY KEY(id))"; + ." id BIGINT NOT NULL," + ." playlist BIGINT NOT NULL," + ." starts TIMESTAMP NOT NULL," + ." ends TIMESTAMP NOT NULL," + ." PRIMARY KEY(id))"; camp_install_query($sql); } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['scheduleTable']."\n"; @@ -364,10 +385,10 @@ if (!camp_db_table_exists($CC_CONFIG['scheduleTable'])) { if (!camp_db_table_exists($CC_CONFIG['playlogTable'])) { echo " * Creating database table ".$CC_CONFIG['playlogTable']."..."; $sql = "CREATE TABLE ".$CC_CONFIG['playlogTable']."(" - ." id BIGINT NOT NULL," - ." audioClipId BIGINT NOT NULL," - ." timestamp TIMESTAMP NOT NULL," - ." PRIMARY KEY(id))"; + ." id BIGINT NOT NULL," + ." audioClipId BIGINT NOT NULL," + ." timestamp TIMESTAMP NOT NULL," + ." PRIMARY KEY(id))"; camp_install_query($sql); } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['playlogTable']."\n"; @@ -377,12 +398,12 @@ if (!camp_db_table_exists($CC_CONFIG['playlogTable'])) { if (!camp_db_table_exists($CC_CONFIG['backupTable'])) { echo " * Creating database table ".$CC_CONFIG['backupTable']."..."; $sql = "CREATE TABLE ".$CC_CONFIG['backupTable']." (" - ." token VARCHAR(64) NOT NULL," - ." sessionId VARCHAR(64) NOT NULL," - ." status VARCHAR(32) NOT NULL," - ." fromTime TIMESTAMP NOT NULL," - ." toTime TIMESTAMP NOT NULL," - ." PRIMARY KEY(token))"; + ." token VARCHAR(64) NOT NULL," + ." sessionId VARCHAR(64) NOT NULL," + ." status VARCHAR(32) NOT NULL," + ." fromTime TIMESTAMP NOT NULL," + ." toTime TIMESTAMP NOT NULL," + ." PRIMARY KEY(token))"; camp_install_query($sql); } else { echo " * Skipping: database table already exists: ".$CC_CONFIG['backupTable']."\n"; @@ -390,7 +411,7 @@ if (!camp_db_table_exists($CC_CONFIG['backupTable'])) { if (!camp_db_table_exists($CC_CONFIG['prefTable'])) { echo " * Creating database table ".$CC_CONFIG['prefTable']."..."; - $CC_DBC->createSequence($CC_CONFIG['prefTable']."_id_seq"); + //$CC_DBC->createSequence($CC_CONFIG['prefSequence']); $sql = "CREATE TABLE ".$CC_CONFIG['prefTable']." ( id int not null, subjid int REFERENCES ".$CC_CONFIG['subjTable']." ON DELETE CASCADE, @@ -478,7 +499,7 @@ $cron = new Cron(); $access = $cron->openCrontab('write'); if ($access != 'write') { do { - $r = $cron->forceWriteable(); + $r = $cron->forceWriteable(); } while ($r); } diff --git a/src/modules/storageServer/var/install/uninstall.php b/src/modules/storageServer/var/install/uninstall.php index 7199e3d69..6c781ace6 100644 --- a/src/modules/storageServer/var/install/uninstall.php +++ b/src/modules/storageServer/var/install/uninstall.php @@ -20,8 +20,8 @@ echo "***************************\n"; echo "* StorageServer Uninstall *\n"; echo "***************************\n"; -require_once('../conf.php'); -require_once('installInit.php'); +require_once(dirname(__FILE__).'/../conf.php'); +require_once(dirname(__FILE__).'/installInit.php'); campcaster_db_connect(false); function camp_uninstall_delete_files($p_path) @@ -47,7 +47,7 @@ if (!PEAR::isError($CC_DBC)) { $sql = "DROP TABLE ".$CC_CONFIG['prefTable']; camp_install_query($sql, false); - $CC_DBC->dropSequence($CC_CONFIG['prefTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['prefTable']."_id"); echo "done.\n"; } else { echo " * Skipping: database table ".$CC_CONFIG['prefTable']."\n"; @@ -88,7 +88,7 @@ if (camp_db_table_exists($CC_CONFIG['transTable'])) { $sql = "DROP TABLE ".$CC_CONFIG['transTable']; camp_install_query($sql, false); - $CC_DBC->dropSequence($CC_CONFIG['transTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['transTable']."_id"); echo "done.\n"; } else { echo " * Skipping: database table ".$CC_CONFIG['transTable']."\n"; @@ -99,7 +99,7 @@ if (camp_db_table_exists($CC_CONFIG['mdataTable'])) { $sql = "DROP TABLE ".$CC_CONFIG['mdataTable']; camp_install_query($sql, false); - $CC_DBC->dropSequence($CC_CONFIG['mdataTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['mdataTable']."_id"); echo "done.\n"; } else { echo " * Skipping: database table ".$CC_CONFIG['mdataTable']."\n"; @@ -109,15 +109,17 @@ if (camp_db_table_exists($CC_CONFIG['filesTable'])) { echo " * Removing database table ".$CC_CONFIG['filesTable']."..."; $sql = "DROP TABLE ".$CC_CONFIG['filesTable']; camp_install_query($sql); + $CC_DBC->dropSequence($CC_CONFIG['filesTable']."_id"); + } else { echo " * Skipping: database table ".$CC_CONFIG['filesTable']."\n"; } -if (camp_db_sequence_exists($CC_CONFIG['filesSequence'])) { - $sql = "DROP SEQUENCE ".$CC_CONFIG['filesSequence']; - camp_install_query($sql); -} - +//if (camp_db_sequence_exists($CC_CONFIG['filesSequence'])) { +// $sql = "DROP SEQUENCE ".$CC_CONFIG['filesSequence']; +// camp_install_query($sql); +//} +// if (camp_db_table_exists($CC_CONFIG['accessTable'])) { echo " * Removing database table ".$CC_CONFIG['accessTable']."..."; $sql = "DROP TABLE ".$CC_CONFIG['accessTable']; @@ -131,7 +133,7 @@ if (camp_db_table_exists($CC_CONFIG['permTable'])) { $sql = "DROP TABLE ".$CC_CONFIG['permTable']; camp_install_query($sql, false); - $CC_DBC->dropSequence($CC_CONFIG['permTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['permTable']."_id"); echo "done.\n"; } else { echo " * Skipping: database table ".$CC_CONFIG['permTable']."\n"; @@ -147,7 +149,7 @@ if (camp_db_table_exists($CC_CONFIG['sessTable'])) { if (camp_db_table_exists($CC_CONFIG['subjTable'])) { echo " * Removing database table ".$CC_CONFIG['subjTable']."..."; - $CC_DBC->dropSequence($CC_CONFIG['subjTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['subjTable']."_id"); $sql = "DROP TABLE ".$CC_CONFIG['subjTable']; camp_install_query($sql, false); @@ -162,7 +164,7 @@ if (camp_db_table_exists($CC_CONFIG['smembTable'])) { $sql = "DROP TABLE ".$CC_CONFIG['smembTable']; camp_install_query($sql, false); - $CC_DBC->dropSequence($CC_CONFIG['smembTable']."_id_seq"); + $CC_DBC->dropSequence($CC_CONFIG['smembTable']."_id"); echo "done.\n"; } else { echo " * Skipping: database table ".$CC_CONFIG['smembTable']."\n"; diff --git a/src/modules/storageServer/var/tests/UnitTests.php b/src/modules/storageServer/var/tests/UnitTests.php new file mode 100644 index 000000000..4c9225e5a --- /dev/null +++ b/src/modules/storageServer/var/tests/UnitTests.php @@ -0,0 +1,86 @@ +getMessage()." ".$CC_DBC->getUserInfo()."\n"; + exit(1); +} +$CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC); + +class BasicStorTest extends PHPUnit_TestCase { + + private $greenbox; + + function __construct($name) { + parent::__construct($name); + } + + function setup() { + $this->greenbox = new GreenBox(); + } + + function testGetAudioMetadata() { + $filePath = dirname(__FILE__)."/ex1.mp3"; + $metadata = camp_get_audio_metadata($filePath); + if (PEAR::isError($metadata)) { + $this->fail($metadata->getMessage()); + return; + } + if (($metadata["dc:description"] != "Tmu sem tam videla ...") + || ($metadata["audio"]["dataformat"] != "mp3") + || ($metadata["dc:type"] != "Speech")) { + $str = " [dc:description] = " . $metadata["dc:description"] ."\n" + . " [audio][dataformat] = " . $metadata["audio"]["dataformat"]."\n" + . " [dc:type] = ".$metadata["dc:type"]."\n"; + $this->fail("Metadata has unexpected values:\n".$str); + } + //var_dump($metadata); + } + + function testPutFile() { + $STORAGE_SERVER_PATH = dirname(__FILE__)."/../../"; + $filePath = dirname(__FILE__)."/ex1.mp3"; + $md5sum = md5_file($filePath); + $metadata = camp_get_audio_metadata($filePath); + if (PEAR::isError($metadata)) { + $this->fail($metadata->getMessage()); + return; + } + // bsSetMetadataBatch doesnt like these values + unset($metadata['audio']); + unset($metadata['playtime_seconds']); + $values = array( + "filename" => $metadata['ls:filename'], + "filepath" => $filePath, + "metadata" => "$STORAGE_SERVER_PATH/var/emptyMdata.xml", + "gunid" => NULL, + "filetype" => "audioclip", + "md5" => $md5sum, + "mime" => $metadata['dc:format'] + ); + $storedFile = $this->greenbox->bsPutFile($values, false); + $this->assertFalse(PEAR::isError($storedFile)); + $id = $storedFile->getId(); + if (!is_numeric($id)) { + $this->fail("StoredFile not created correctly. id = ".$id); + return; + } + + $r = $this->greenbox->bsSetMetadataBatch($storedFile, $metadata); + if (PEAR::isError($r)) { + $this->fail($r->getMessage()); + //echo var_export($metadata)."\n"; + return; + } + } + + +} +?> \ No newline at end of file diff --git a/src/modules/storageServer/var/tests/runUnitTests.php b/src/modules/storageServer/var/tests/runUnitTests.php new file mode 100644 index 000000000..9393f37b6 --- /dev/null +++ b/src/modules/storageServer/var/tests/runUnitTests.php @@ -0,0 +1,9 @@ +toString(); +?> \ No newline at end of file diff --git a/src/modules/storageServer/var/tests/transTest.php b/src/modules/storageServer/var/tests/transTest.php index ae5210cca..ae8c7313a 100644 --- a/src/modules/storageServer/var/tests/transTest.php +++ b/src/modules/storageServer/var/tests/transTest.php @@ -1,6 +1,4 @@ . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: PHPUnit.php,v 1.17 2005/11/10 09:47:11 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/TestCase.php'; +require_once 'PHPUnit/TestResult.php'; +require_once 'PHPUnit/TestSuite.php'; + +/** + * PHPUnit runs a TestSuite and returns a TestResult object. + * + * Here is an example: + * + * + * PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * + * function testAdd() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 5); + * } + * } + * + * $suite = new PHPUnit_TestSuite(); + * $suite->addTest(new MathTest('testAdd')); + * + * $result = PHPUnit::run($suite); + * print $result->toHTML(); + * ?> + * + * + * Alternatively, you can pass a class name to the PHPUnit_TestSuite() + * constructor and let it automatically add all methods of that class + * that start with 'test' to the suite: + * + * + * toHTML(); + * ?> + * + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit { + /** + * Runs a test(suite). + * + * @param mixed + * @return PHPUnit_TestResult + * @access public + */ + function &run(&$suite) { + $result = new PHPUnit_TestResult(); + $suite->run($result); + + return $result; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/Assert.php b/src/tools/pear/src/PHPUnit/Assert.php new file mode 100644 index 000000000..6895e4d35 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/Assert.php @@ -0,0 +1,426 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Assert.php,v 1.29 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +/** + * A set of assert methods. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_Assert { + /** + * @var boolean + * @access private + */ + var $_looselyTyped = FALSE; + + /** + * Asserts that a haystack contains a needle. + * + * @param mixed + * @param mixed + * @param string + * @access public + * @since Method available since Release 1.1.0 + */ + function assertContains($needle, $haystack, $message = '') { + if (is_string($needle) && is_string($haystack)) { + $this->assertTrue(strpos($haystack, $needle) !== FALSE, $message); + } + + else if (is_array($haystack) && !is_object($needle)) { + $this->assertTrue(in_array($needle, $haystack), $message); + } + + else { + $this->fail('Unsupported parameter passed to assertContains().'); + } + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @param mixed + * @param mixed + * @param string + * @access public + * @since Method available since Release 1.1.0 + */ + function assertNotContains($needle, $haystack, $message = '') { + if (is_string($needle) && is_string($haystack)) { + $this->assertFalse(strpos($haystack, $needle) !== FALSE, $message); + } + + else if (is_array($haystack) && !is_object($needle)) { + $this->assertFalse(in_array($needle, $haystack), $message); + } + + else { + $this->fail('Unsupported parameter passed to assertNotContains().'); + } + } + + /** + * Asserts that two variables are equal. + * + * @param mixed + * @param mixed + * @param string + * @param mixed + * @access public + */ + function assertEquals($expected, $actual, $message = '', $delta = 0) { + if ((is_array($actual) && is_array($expected)) || + (is_object($actual) && is_object($expected))) { + if (is_array($actual) && is_array($expected)) { + ksort($actual); + ksort($expected); + } + + if ($this->_looselyTyped) { + $actual = $this->_convertToString($actual); + $expected = $this->_convertToString($expected); + } + + $actual = serialize($actual); + $expected = serialize($expected); + + $message = sprintf( + '%sexpected %s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + $actual + ); + + if ($actual !== $expected) { + return $this->fail($message); + } + } + + elseif (is_numeric($actual) && is_numeric($expected)) { + $message = sprintf( + '%sexpected %s%s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + ($delta != 0) ? ('+/- ' . $delta) : '', + $actual + ); + + if (!($actual >= ($expected - $delta) && $actual <= ($expected + $delta))) { + return $this->fail($message); + } + } + + else { + $message = sprintf( + '%sexpected %s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + $actual + ); + + if ($actual !== $expected) { + return $this->fail($message); + } + } + } + + /** + * Asserts that two variables reference the same object. + * This requires the Zend Engine 2 to work. + * + * @param object + * @param object + * @param string + * @access public + * @deprecated + */ + function assertSame($expected, $actual, $message = '') { + if (!version_compare(phpversion(), '5.0.0', '>=')) { + $this->fail('assertSame() only works with PHP >= 5.0.0.'); + } + + if ((is_object($expected) || is_null($expected)) && + (is_object($actual) || is_null($actual))) { + $message = sprintf( + '%sexpected two variables to reference the same object', + + !empty($message) ? $message . ' ' : '' + ); + + if ($expected !== $actual) { + return $this->fail($message); + } + } else { + $this->fail('Unsupported parameter passed to assertSame().'); + } + } + + /** + * Asserts that two variables do not reference the same object. + * This requires the Zend Engine 2 to work. + * + * @param object + * @param object + * @param string + * @access public + * @deprecated + */ + function assertNotSame($expected, $actual, $message = '') { + if (!version_compare(phpversion(), '5.0.0', '>=')) { + $this->fail('assertNotSame() only works with PHP >= 5.0.0.'); + } + + if ((is_object($expected) || is_null($expected)) && + (is_object($actual) || is_null($actual))) { + $message = sprintf( + '%sexpected two variables to reference different objects', + + !empty($message) ? $message . ' ' : '' + ); + + if ($expected === $actual) { + return $this->fail($message); + } + } else { + $this->fail('Unsupported parameter passed to assertNotSame().'); + } + } + + /** + * Asserts that a variable is not NULL. + * + * @param mixed + * @param string + * @access public + */ + function assertNotNull($actual, $message = '') { + $message = sprintf( + '%sexpected NOT NULL, actual NULL', + + !empty($message) ? $message . ' ' : '' + ); + + if (is_null($actual)) { + return $this->fail($message); + } + } + + /** + * Asserts that a variable is NULL. + * + * @param mixed + * @param string + * @access public + */ + function assertNull($actual, $message = '') { + $message = sprintf( + '%sexpected NULL, actual NOT NULL', + + !empty($message) ? $message . ' ' : '' + ); + + if (!is_null($actual)) { + return $this->fail($message); + } + } + + /** + * Asserts that a condition is true. + * + * @param boolean + * @param string + * @access public + */ + function assertTrue($condition, $message = '') { + $message = sprintf( + '%sexpected TRUE, actual FALSE', + + !empty($message) ? $message . ' ' : '' + ); + + if (!$condition) { + return $this->fail($message); + } + } + + /** + * Asserts that a condition is false. + * + * @param boolean + * @param string + * @access public + */ + function assertFalse($condition, $message = '') { + $message = sprintf( + '%sexpected FALSE, actual TRUE', + + !empty($message) ? $message . ' ' : '' + ); + + if ($condition) { + return $this->fail($message); + } + } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string + * @param string + * @param string + * @access public + */ + function assertRegExp($pattern, $string, $message = '') { + $message = sprintf( + '%s"%s" does not match pattern "%s"', + + !empty($message) ? $message . ' ' : '', + $string, + $pattern + ); + + if (!preg_match($pattern, $string)) { + return $this->fail($message); + } + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @param string + * @param string + * @param string + * @access public + * @since Method available since Release 1.1.0 + */ + function assertNotRegExp($pattern, $string, $message = '') { + $message = sprintf( + '%s"%s" matches pattern "%s"', + + !empty($message) ? $message . ' ' : '', + $string, + $pattern + ); + + if (preg_match($pattern, $string)) { + return $this->fail($message); + } + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param optional string $message + * @access public + */ + function assertType($expected, $actual, $message = '') { + return $this->assertEquals( + $expected, + gettype($actual), + $message + ); + } + + /** + * Converts a value to a string. + * + * @param mixed $value + * @access private + */ + function _convertToString($value) { + foreach ($value as $k => $v) { + if (is_array($v)) { + $value[$k] = $this->_convertToString($value[$k]); + } else { + settype($value[$k], 'string'); + } + } + + return $value; + } + + /** + * @param boolean $looselyTyped + * @access public + */ + function setLooselyTyped($looselyTyped) { + if (is_bool($looselyTyped)) { + $this->_looselyTyped = $looselyTyped; + } + } + + /** + * Fails a test with the given message. + * + * @param string + * @access protected + * @abstract + */ + function fail($message = '') { /* abstract */ } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/GUI/Gtk.php b/src/tools/pear/src/PHPUnit/GUI/Gtk.php new file mode 100644 index 000000000..3649dc2db --- /dev/null +++ b/src/tools/pear/src/PHPUnit/GUI/Gtk.php @@ -0,0 +1,740 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Scott Mattocks + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Gtk.php,v 1.6 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.2.0 + */ + +if (!function_exists('is_a')) { + require_once 'PHP/Compat/Function/is_a.php'; +} + +/** + * GTK GUI interface for PHPUnit. + * + * This class is a PHP port of junit.awtui.testrunner. Documentation + * for junit.awtui.testrunner can be found at + * http://junit.sourceforge.net + * + * Due to the limitations of PHP4 and PHP-Gtk, this class can not + * duplicate all of the functionality of the JUnit GUI. Some of the + * things this class cannot do include: + * - Reloading the class for each run + * - Stopping the test in progress + * + * To use simply intantiate the class and call main() + * $gtk =& new PHPUnit_GUI_Gtk; + * $gtk->main(); + * + * Once the window has finished loading, you can enter the name of + * a class that has been loaded (include/require some where in your + * code, or you can pass the name of the file containing the class. + * + * You can also load classes using the SetupDecorator class. + * require_once 'PHPUnit/GUI/SetupDecorator.php'; + * require_once 'PHPUnit/GUI/Gtk.php'; + * $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_Gtk()); + * $gui->getSuitesFromDir('/path/to/test','.*\.php$',array('index.php','sql.php')); + * $gui->show(); + * + * + * @category Testing + * @package PHPUnit + * @author Scott Mattocks + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.2.0 + * @todo Allow file drop. (Gtk_FileDrop) + */ +class PHPUnit_GUI_Gtk { + + /** + * The main gtk window + * @var object + */ + var $gui; + /** + * The text entry that contains the name of the + * file that holds the test(s)/suite(s). + * @var object + */ + var $suiteField; + /** + * The label that shows the number of tests that + * were run. + * @var object + */ + var $numberOfRuns; + /** + * The label that shows the number of errors that + * were encountered. + * @var object + */ + var $numberOfErrors; + /** + * The label that shows the number of failures + * that were encountered. + * @var object + */ + var $numberOfFailures; + /** + * The label for reporting user messages. + * @var object + */ + var $statusLine; + /** + * The text area for reporting messages from successful + * test runs. (not necessarily successful tests) + * @var object + */ + var $reportArea; + /** + * The text area for reporting errors encountered when + * running tests. + * @var object + */ + var $dumpArea; + /** + * The progress bar indicator. Shows the percentage of + * passed tests. + * @var object + */ + var $progress; + /** + * A checkbox for the user to indicate whether or not they + * would like to see results from all tests or just failures. + * @object + */ + var $showPassed; + + /** + * Constructor. + * + * The constructor checks for the gtk extension and loads it + * if needed. Then it creates the GUI. The GUI is not shown + * nor is the main gtk loop started until main() is called. + * + * @access public + * @param none + * @return void + */ + function PHPUnit_GUI_Gtk() + { + // Check for php-gtk extension. + if (!extension_loaded('gtk')) { + dl( 'php_gtk.' . PHP_SHLIB_SUFFIX); + } + + // Create the interface but don't start the loop + $this->_createUI(); + } + /** + * Start the main gtk loop. + * + * main() first sets the default state of the showPassed + * check box. Next all widgets that are part of the GUI + * are shown. Finally the main gtk loop is started. + * + * @access public + * @param boolean $showPassed + * @return void + */ + function main($showPassed = true) + { + $this->showPassed->set_active($showPassed); + $this->gui->show_all(); + + gtk::main(); + } + /** + * Create the user interface. + * + * The user interface is pretty simple. It consists of a + * menu, text entry, run button, some labels, a progress + * indicator, and a couple of areas for notification of + * any messages. + * + * @access private + * @param none + * @return void + */ + function _createUI() + { + // Create a window. + $window =& new GtkWindow; + $window->set_title('PHPUnit Gtk'); + $window->set_usize(400, -1); + + // Create the main box. + $mainBox =& new GtkVBox; + $window->add($mainBox); + + // Start with the menu. + $mainBox->pack_start($this->_createMenu()); + + // Then add the suite field entry. + $mainBox->pack_start($this->_createSuiteEntry()); + + // Then add the report labels. + $mainBox->pack_start($this->_createReportLabels()); + + // Next add the progress bar. + $mainBox->pack_start($this->_createProgressBar()); + + // Then add the report area and the dump area. + $mainBox->pack_start($this->_createReportAreas()); + + // Finish off with the status line. + $mainBox->pack_start($this->_createStatusLine()); + + // Connect the destroy signal. + $window->connect_object('destroy', array('gtk', 'main_quit')); + + // Assign the member. + $this->gui =& $window; + } + /** + * Create the menu. + * + * The menu is very simple. It an exit menu item, which exits + * the application, and an about menu item, which shows some + * basic information about the application itself. + * + * @access private + * @param none + * @return &object The GtkMenuBar + */ + function &_createMenu() + { + // Create the menu bar. + $menuBar =& new GtkMenuBar; + + // Create the main (only) menu item. + $phpHeader =& new GtkMenuItem('PHPUnit'); + + // Add the menu item to the menu bar. + $menuBar->append($phpHeader); + + // Create the PHPUnit menu. + $phpMenu =& new GtkMenu; + + // Add the menu items + $about =& new GtkMenuItem('About...'); + $about->connect('activate', array(&$this, 'about')); + $phpMenu->append($about); + + $exit =& new GtkMenuItem('Exit'); + $exit->connect_object('activate', array('gtk', 'main_quit')); + $phpMenu->append($exit); + + // Complete the menu. + $phpHeader->set_submenu($phpMenu); + + return $menuBar; + } + /** + * Create the suite entry and related widgets. + * + * The suite entry has some supporting components such as a + * label, the show passed check box and the run button. All + * of these items are packed into two nested boxes. + * + * @access private + * @param none + * @return &object A box that contains all of the suite entry pieces. + */ + function &_createSuiteEntry() + { + // Create the outermost box. + $outerBox =& new GtkVBox; + + // Create the suite label, box, and field. + $suiteLabel =& new GtkLabel('Test class name:'); + $suiteBox =& new GtkHBox; + $this->suiteField =& new GtkEntry; + $this->suiteField->set_text($suiteName != NULL ? $suiteName : ''); + + // Create the button the user will use to start the test. + $runButton =& new GtkButton('Run'); + $runButton->connect_object('clicked', array(&$this, 'run')); + + // Create the check box that lets the user show only failures. + $this->showPassed =& new GtkCheckButton('Show passed tests'); + + // Add the components to their respective boxes. + $suiteLabel->set_alignment(0, 0); + $outerBox->pack_start($suiteLabel); + $outerBox->pack_start($suiteBox); + $outerBox->pack_start($this->showPassed); + + $suiteBox->pack_start($this->suiteField); + $suiteBox->pack_start($runButton); + + return $outerBox; + } + + /** + * Create the labels that tell the user what has happened. + * + * There are three labels, one each for total runs, errors and + * failures. There is also one label for each of these that + * describes what the label is. It could be done with one label + * instead of two but that would make updates much harder. + * + * @access private + * @param none + * @return &object A box containing the labels. + */ + function &_createReportLabels() + { + // Create a box to hold everything. + $labelBox =& new GtkHBox; + + // Create the non-updated labels. + $numberOfRuns =& new GtkLabel('Runs:'); + $numberOfErrors =& new GtkLabel('Errors:'); + $numberOfFailures =& new GtkLabel('Failures:'); + + // Create the labels that will be updated. + // These are asssigned to members to make it easier to + // set their values later. + $this->numberOfRuns =& new GtkLabel(0); + $this->numberOfErrors =& new GtkLabel(0); + $this->numberOfFailures =& new GtkLabel(0); + + // Pack everything in. + $labelBox->pack_start($numberOfRuns); + $labelBox->pack_start($this->numberOfRuns); + $labelBox->pack_start($numberOfErrors); + $labelBox->pack_start($this->numberOfErrors); + $labelBox->pack_start($numberOfFailures); + $labelBox->pack_start($this->numberOfFailures); + + return $labelBox; + } + + /** + * Create the success/failure indicator. + * + * A GtkProgressBar is used to visually indicate how many + * tests were successful compared to how many were not. The + * progress bar shows the percentage of success and will + * change from green to red if there are any failures. + * + * @access private + * @param none + * @return &object The progress bar + */ + function &_createProgressBar() + { + // Create the progress bar. + $this->progress =& new GtkProgressBar(new GtkAdjustment(0, 0, 1, .1, 1, 0)); + + // Set the progress bar to print the percentage. + $this->progress->set_show_text(true); + + return $this->progress; + } + + /** + * Create the report text areas. + * + * The report area consists of one text area for failures, one + * text area for errors and one label for identification purposes. + * All three widgets are packed into a box. + * + * @access private + * @param none + * @return &object The box containing the report areas. + */ + function &_createReportAreas() + { + // Create the containing box. + $reportBox =& new GtkVBox; + + // Create the identification label + $reportLabel =& new GtkLabel('Errors and Failures:'); + $reportLabel->set_alignment(0, 0); + + // Create the scrolled windows for the text areas. + $reportScroll =& new GtkScrolledWindow; + $dumpScroll =& new GtkScrolledWindow; + + // Make the scroll areas big enough. + $reportScroll->set_usize(-1, 150); + $dumpScroll->set_usize(-1, 150); + + // Only show the vertical scroll bar when needed. + // Never show the horizontal scroll bar. + $reportScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + $dumpScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + // Create the text areas. + $this->reportArea =& new GtkText; + $this->dumpArea =& new GtkText; + + // Don't let words get broken. + $this->reportArea->set_word_wrap(true); + $this->dumpArea->set_word_wrap(true); + + // Pack everything in. + $reportBox->pack_start($reportLabel); + $reportScroll->add($this->reportArea); + $reportBox->pack_start($reportScroll); + $dumpScroll->add($this->dumpArea); + $reportBox->pack_start($dumpScroll); + + return $reportBox; + } + + /** + * Create a status label. + * + * A status line at the bottom of the application is used + * to notify the user of non-test related messages such as + * failures loading a test suite. + * + * @access private + * @param none + * @return &object The status label. + */ + function &_createStatusLine() + { + // Create the status label. + $this->statusLine =& new GtkLabel(''); + $this->statusLine->set_alignment(0, 0); + + return $this->statusLine; + } + + /** + * Show a popup with information about the application. + * + * The popup should show information about the version, + * the author, the license, where to get the latest + * version and a short description. + * + * @access public + * @param none + * @return void + */ + function about() + { + // Create the new window. + $about =& new GtkWindow; + $about->set_title('About PHPUnit GUI Gtk'); + $about->set_usize(250, -1); + + // Put two vboxes in the hbox. + $vBox =& new GtkVBox; + $about->add($vBox); + + // Create the labels. + $version =& new GtkLabel(" Version: 1.0"); + $license =& new GtkLabel(" License: PHP License v3.0"); + $where =& new GtkLabel(" Download from: http://pear.php.net/PHPUnit/"); + $unitAuth =& new GtkLabel(" PHPUnit Author: Sebastian Bergman"); + $gtkAuth =& new GtkLabel(" Gtk GUI Author: Scott Mattocks"); + + // Align everything to the left + $where->set_alignment(0, .5); + $version->set_alignment(0, .5); + $license->set_alignment(0, .5); + $gtkAuth->set_alignment(0, .5); + $unitAuth->set_alignment(0, .5); + + // Pack everything into the vBox; + $vBox->pack_start($version); + $vBox->pack_start($license); + $vBox->pack_start($where); + $vBox->pack_start($unitAuth); + $vBox->pack_start($gtkAuth); + + // Connect the destroy signal. + $about->connect('destroy', array('gtk', 'true')); + + // Show the goods. + $about->show_all(); + } + + /** + * Load the test suite. + * + * This method tries to load test suite based on the user + * info. If the user passes the name of a tests suite, it + * is instantiated and a new object is returned. If the + * user passes a file that contains a test suite, the class + * is instantiated and a new object is returned. If the user + * passes a file that contains a test case, the test case is + * passed to a new test suite and the new suite object is + * returned. + * + * @access public + * @param string The file that contains a test case/suite or the classname. + * @return &object The new test suite. + */ + function &loadTest(&$file) + { + // Check to see if a class name was given. + if (is_a($file, 'PHPUnit_TestSuite')) { + return $file; + } elseif (class_exists($file)) { + require_once 'PHPUnit/TestSuite.php'; + return new PHPUnit_TestSuite($file); + } + + // Check that the file exists. + if (!@is_readable($file)) { + $this->_showStatus('Cannot find file: ' . $file); + return false; + } + + $this->_showStatus('Loading test suite...'); + + // Instantiate the class. + // If the path is /path/to/test/TestClass.php + // the class name should be test_TestClass + require_once $file; + $className = str_replace(DIRECTORY_SEPARATOR, '_', $file); + $className = substr($className, 0, strpos($className, '.')); + + require_once 'PHPUnit/TestSuite.php'; + return new PHPUnit_TestSuite($className); + } + + /** + * Run the test suite. + * + * This method runs the test suite and updates the messages + * for the user. When finished it changes the status line + * to 'Test Complete' + * + * @access public + * @param none + * @return void + */ + function runTest() + { + // Notify the user that the test is running. + $this->_showStatus('Running Test...'); + + // Run the test. + $result = PHPUnit::run($this->suite); + + // Update the labels. + $this->_setLabelValue($this->numberOfRuns, $result->runCount()); + $this->_setLabelValue($this->numberOfErrors, $result->errorCount()); + $this->_setLabelValue($this->numberOfFailures, $result->failureCount()); + + // Update the progress bar. + $this->_updateProgress($result->runCount(), + $result->errorCount(), + $result->failureCount() + ); + + // Show the errors. + $this->_showFailures($result->errors(), $this->dumpArea); + + // Show the messages from the tests. + if ($this->showPassed->get_active()) { + // Show failures and success. + $this->_showAll($result, $this->reportArea); + } else { + // Show only failures. + $this->_showFailures($result->failures(), $this->reportArea); + } + + // Update the status message. + $this->_showStatus('Test complete'); + } + + /** + * Set the text of a label. + * + * Change the text of a given label. + * + * @access private + * @param widget &$label The label whose value is to be changed. + * @param string $value The new text of the label. + * @return void + */ + function _setLabelValue(&$label, $value) + { + $label->set_text($value); + } + + /** + * The main work of the application. + * + * Load the test suite and then execute the tests. + * + * @access public + * @param none + * @return void + */ + function run() + { + // Load the test suite. + $this->suite =& $this->loadTest($this->suiteField->get_text()); + + // Check to make sure the suite was loaded properly. + if (!is_object($this->suite)) { + // Raise an error. + $this->_showStatus('Could not load test suite.'); + return false; + } + + // Run the tests. + $this->runTest(); + } + + /** + * Update the status message. + * + * @access private + * @param string $status The new message. + * @return void + */ + function _showStatus($status) + { + $this->statusLine->set_text($status); + } + + /** + * Alias for main() + * + * @see main + */ + function show($showPassed = true) + { + $this->main($showPassed); + } + + /** + * Add a suite to the tests. + * + * This method is require by SetupDecorator. It adds a + * suite to the the current set of suites. + * + * @access public + * @param object $testSuite The suite to add. + * @return void + */ + function addSuites($testSuite) + { + if (!is_array($testSuite)) { + settype($testSuite, 'array'); + } + + foreach ($testSuite as $suite) { + + if (is_a($this->suite, 'PHPUnit_TestSuite')) { + $this->suite->addTestSuite($suite->getName()); + } else { + $this->suite =& $this->loadTest($suite); + } + + // Set the suite field. + $text = $this->suiteField->get_text(); + if (empty($text)) { + $this->suiteField->set_text($this->suite->getName()); + } + } + } + + /** + * Show all test messages. + * + * @access private + * @param object The TestResult from the test suite. + * @return void + */ + function _showAll(&$result) + { + // Clear the area first. + $this->reportArea->delete_text(0, -1); + $this->reportArea->insert_text($result->toString(), 0); + } + + /** + * Show failure/error messages in the given text area. + * + * @access private + * @param object &$results The results of the test. + * @param widget &$area The area to show the results in. + */ + function _showFailures(&$results, &$area) + { + $area->delete_text(0, -1); + foreach (array_reverse($results, true) as $result) { + $area->insert_text($result->toString(), 0); + } + } + + /** + * Update the progress indicator. + * + * @access private + * @param integer $runs + * @param integer $errors + * @param integer $failures + * @return void + */ + function _updateProgress($runs, $errors, $failures) + { + $percentage = 1 - (($errors + $failures) / $runs); + $this->progress->set_percentage($percentage); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/GUI/HTML.php b/src/tools/pear/src/PHPUnit/GUI/HTML.php new file mode 100644 index 000000000..f2816ef4c --- /dev/null +++ b/src/tools/pear/src/PHPUnit/GUI/HTML.php @@ -0,0 +1,252 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Wolfram Kriesing + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: HTML.php,v 1.19 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +/** + * HTML GUI. + * + * @category Testing + * @package PHPUnit + * @author Wolfram Kriesing + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_GUI_HTML +{ + var $_suites = array(); + + /** + * the current implementation of PHPUnit is designed + * this way that adding a suite to another suite only + * grabs all the tests and adds them to the suite, so you + * have no chance to find out which test goes with which suite + * therefore you can simply pass an array of suites to this constructor here + * + * @param array The suites to be tested. If not given, then you might + * be using the SetupDecorator, which detects them automatically + * when calling getSuitesFromDir() + */ + function PHPUnit_GUI_HTML($suites = array()) + { + if (!is_array($suites)) { + $this->_suites = array($suites); + } else { + $this->_suites = $suites; + } + } + + /** + * Add suites to the GUI + * + * @param object this should be an instance of PHPUnit_TestSuite + */ + function addSuites($suites) + { + $this->_suites = array_merge($this->_suites,$suites); + } + + /** + * this prints the HTML code straight out + * + */ + function show() + { + $request = $_REQUEST; + $showPassed = FALSE; + $submitted = @$request['submitted']; + + if ($submitted) { + $showPassed = @$request['showOK'] ? TRUE : FALSE; + } + + $suiteResults = array(); + + foreach ($this->_suites as $aSuite) { + $aSuiteResult = array(); + + // remove the first directory's name from the test-suite name, since it + // mostly is something like 'tests' or alike + $removablePrefix = explode('_',$aSuite->getName()); + $aSuiteResult['name'] = str_replace($removablePrefix[0].'_', '', $aSuite->getName()); + + if ($submitted && isset($request[$aSuiteResult['name']])) { + $result = PHPUnit::run($aSuite); + + $aSuiteResult['counts']['run'] = $result->runCount(); + $aSuiteResult['counts']['error'] = $result->errorCount(); + $aSuiteResult['counts']['failure'] = $result->failureCount(); + + $aSuiteResult['results'] = $this->_prepareResult($result,$showPassed); + + $per = 100/$result->runCount(); + $failed = ($per*$result->errorCount())+($per*$result->failureCount()); + $aSuiteResult['percent'] = round(100-$failed,2); + } else { + $aSuiteResult['addInfo'] = 'NOT EXECUTED'; + } + + $suiteResults[] = $aSuiteResult; + } + + $final['name'] = 'OVERALL RESULT'; + $final['counts'] = array(); + $final['percent'] = 0; + $numExecutedTests = 0; + + foreach ($suiteResults as $aSuiteResult) { + if (sizeof(@$aSuiteResult['counts'])) { + foreach ($aSuiteResult['counts'] as $key=>$aCount) { + if (!isset($final['counts'][$key])) { + $final['counts'][$key] = 0; + } + + $final['counts'][$key] += $aCount; + } + } + } + + if (isset($final['counts']['run'])) { + $per = 100/$final['counts']['run']; + $failed = ($per*$final['counts']['error'])+($per*$final['counts']['failure']); + $final['percent'] = round(100-$failed,2); + } else { + $final['percent'] = 0; + } + + array_unshift($suiteResults,$final); + + include 'PHPUnit/GUI/HTML.tpl'; + } + + function _prepareResult($result,$showPassed) + { + $ret = array(); + $failures = $result->failures(); + + foreach($failures as $aFailure) { + $ret['failures'][] = $this->_prepareFailure($aFailure); + } + + $errors = $result->errors(); + + foreach($errors as $aError) { + $ret['errors'][] = $this->_prepareErrors($aError); + } + + if ($showPassed) { + $passed = $result->passedTests(); + + foreach($passed as $aPassed) { + $ret['passed'][] = $this->_preparePassedTests($aPassed); + } + } + + return $ret; + } + + function _prepareFailure($failure) + { + $test = $failure->failedTest(); + $ret['testName'] = $test->getName(); + $exception = $failure->thrownException(); + + // a serialized string starts with a 'character:decimal:{' + // if so we try to unserialize it + // this piece of the regular expression is for detecting a serialized + // type like 'a:3:' for an array with three element or an object i.e. 'O:12:"class":3' + $serialized = '(\w:\d+:(?:"[^"]+":\d+:)?\{.*\})'; + + // Spaces might make a diff, so we shall show them properly (since a + // user agent ignores them). + if (preg_match('/^(.*)expected ' . $serialized . ', actual ' . $serialized . '$/sU', $exception, $matches)) { + ob_start(); + print_r(unserialize($matches[2])); + $ret['expected'] = htmlspecialchars($matches[1]) . "
" . htmlspecialchars(rtrim(ob_get_contents())) . "
"; + // Improved compatibility, ob_clean() would be PHP >= 4.2.0 only. + ob_end_clean(); + + ob_start(); + print_r(unserialize($matches[3])); + $ret['actual'] = htmlspecialchars($matches[1]) . "
" . htmlspecialchars(rtrim(ob_get_contents())) . "
"; + ob_end_clean(); + } + + else if (preg_match('/^(.*)expected (.*), actual (.*)$/sU', $exception, $matches)) { + $ret['expected'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[2]))); + $ret['actual'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[3]))); + } else { + $ret['message'] = nl2br(str_replace(" ", " ", htmlspecialchars($exception))); + } + + return $ret; + } + + function _preparePassedTests($passed) + { + $ret['testName'] = $passed->getName(); + return $ret; + } + + function _prepareError($error) + { + $ret['testName'] = $error->getName(); + $ret['message'] = $error->toString(); + return $ret; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/GUI/HTML.tpl b/src/tools/pear/src/PHPUnit/GUI/HTML.tpl new file mode 100644 index 000000000..edf7f2539 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/GUI/HTML.tpl @@ -0,0 +1,156 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Options +
+ + (un)check all +     + show OK > +     + +
+ > + +   + + + +
+ + + + + +
+ + + +
+
+ $value): ?> + s =         + +
+ + + + + + + + + + + + +
expected
actual
+ +
+ +
OK
+
+ + + + + diff --git a/src/tools/pear/src/PHPUnit/GUI/SetupDecorator.php b/src/tools/pear/src/PHPUnit/GUI/SetupDecorator.php new file mode 100644 index 000000000..8c871fa43 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/GUI/SetupDecorator.php @@ -0,0 +1,209 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Wolfram Kriesing + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: SetupDecorator.php,v 1.15 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +/** + * This decorator actually just adds the functionality to read the + * test-suite classes from a given directory and instanciate them + * automatically, use it as given in the example below. + * + * + * getSuitesFromDir('/path/to/dir/tests','.*\.php$',array('index.php','sql.php')); + * $gui->show(); + * ?> + * + * + * The example calls this class and tells it to: + * + * - find all file under the directory /path/to/dir/tests + * - for files, which end with '.php' (this is a piece of a regexp, that's why the . is escaped) + * - and to exclude the files 'index.php' and 'sql.php' + * - and include all the files that are left in the tests. + * + * Given that the path (the first parameter) ends with 'tests' it will be assumed + * that the classes are named tests_* where * is the directory plus the filename, + * according to PEAR standards. + * + * So that: + * + * - 'testMe.php' in the dir 'tests' bill be assumed to contain a class tests_testMe + * - '/moretests/aTest.php' should contain a class 'tests_moretests_aTest' + * + * @category Testing + * @package PHPUnit + * @author Wolfram Kriesing + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_GUI_SetupDecorator +{ + /** + * + * + */ + function PHPUnit_GUI_SetupDecorator(&$gui) + { + $this->_gui = &$gui; + } + + /** + * just forwarding the action to the decorated class. + * + */ + function show($showPassed=TRUE) + { + $this->_gui->show($showPassed); + } + + /** + * Setup test suites that can be found in the given directory + * Using the second parameter you can also choose a subsets of the files found + * in the given directory. I.e. only all the files that contain '_UnitTest_', + * in order to do this simply call it like this: + * getSuitesFromDir($dir,'.*_UnitTest_.*'). + * There you can already see that the pattern is built for the use within a regular expression. + * + * @param string the directory where to search for test-suite files + * @param string the pattern (a regexp) by which to find the files + * @param array an array of file names that shall be excluded + */ + function getSuitesFromDir($dir, $filenamePattern = '', $exclude = array()) + { + if ($dir{strlen($dir)-1} == DIRECTORY_SEPARATOR) { + $dir = substr($dir, 0, -1); + } + + $files = $this->_getFiles(realpath($dir), $filenamePattern, $exclude, realpath($dir . '/..')); + asort($files); + + foreach ($files as $className => $aFile) { + include_once($aFile); + + if (class_exists($className)) { + $suites[] =& new PHPUnit_TestSuite($className); + } else { + trigger_error("$className could not be found in $dir$aFile!"); + } + } + + $this->_gui->addSuites($suites); + } + + /** + * This method searches recursively through the directories + * to find all the files that shall be added to the be visible. + * + * @param string the path where find the files + * @param srting the string pattern by which to find the files + * @param string the file names to be excluded + * @param string the root directory, which serves as the prefix to the fully qualified filename + * @access private + */ + function _getFiles($dir, $filenamePattern, $exclude, $rootDir) + { + $files = array(); + + if ($dp = opendir($dir)) { + while (FALSE !== ($file = readdir($dp))) { + $filename = $dir . DIRECTORY_SEPARATOR . $file; + $match = TRUE; + + if ($filenamePattern && !preg_match("~$filenamePattern~", $file)) { + $match = FALSE; + } + + if (sizeof($exclude)) { + foreach ($exclude as $aExclude) { + if (strpos($file, $aExclude) !== FALSE) { + $match = FALSE; + break; + } + } + } + + if (is_file($filename) && $match) { + $tmp = str_replace($rootDir, '', $filename); + + if (strpos($tmp, DIRECTORY_SEPARATOR) === 0) { + $tmp = substr($tmp, 1); + } + + if (strpos($tmp, '/') === 0) { + $tmp = substr($tmp, 1); + } + + $className = str_replace(DIRECTORY_SEPARATOR, '_', $tmp); + $className = basename($className, '.php'); + + $files[$className] = $filename; + } + + if ($file != '.' && $file != '..' && is_dir($filename)) { + $files = array_merge($files, $this->_getFiles($filename, $filenamePattern, $exclude, $rootDir)); + } + } + + closedir($dp); + } + + return $files; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/RepeatedTest.php b/src/tools/pear/src/PHPUnit/RepeatedTest.php new file mode 100644 index 000000000..e014eb5ae --- /dev/null +++ b/src/tools/pear/src/PHPUnit/RepeatedTest.php @@ -0,0 +1,154 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: RepeatedTest.php,v 1.13 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/TestDecorator.php'; + +/** + * A Decorator that runs a test repeatedly. + * + * Here is an example: + * + * + * PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * + * function testAdd() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 5); + * } + * } + * + * $suite = new PHPUnit_TestSuite; + * + * $suite->addTest( + * new PHPUnit_RepeatedTest( + * new MathTest('testAdd'), + * 10 + * ) + * ); + * + * $result = PHPUnit::run($suite); + * print $result->toString(); + * ?> + * + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_RepeatedTest extends PHPUnit_TestDecorator { + /** + * @var integer + * @access private + */ + var $_timesRepeat = 1; + + /** + * Constructor. + * + * @param object + * @param integer + * @access public + */ + function PHPUnit_RepeatedTest(&$test, $timesRepeat = 1) { + $this->PHPUnit_TestDecorator($test); + $this->_timesRepeat = $timesRepeat; + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + return $this->_timesRepeat * $this->_test->countTestCases(); + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param object + * @access public + * @abstract + */ + function run(&$result) { + for ($i = 0; $i < $this->_timesRepeat; $i++) { + $this->_test->run($result); + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/Skeleton.php b/src/tools/pear/src/PHPUnit/Skeleton.php new file mode 100644 index 000000000..e316373e0 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/Skeleton.php @@ -0,0 +1,448 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Scott Mattocks + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: Skeleton.php,v 1.8 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.1.0 + */ + +/** + * Class for creating a PHPUnit_TestCase skeleton file. + * + * This class will take a classname as a parameter on construction and will + * create a PHP file that contains the skeleton of a PHPUnit_TestCase + * subclass. The test case will contain a test foreach method of the class. + * Methods of the parent class will, by default, be excluded from the test + * class. Passing and optional construction parameter will include them. + * + * Example + * + * createTestClass(); + * + * // Write the new test class to file. + * // By default, code to run the test will be included. + * $ps->writeTestClass(); + * ?> + * + * Now open the skeleton class and fill in the details. + * If you run the test as is, all tests will fail and + * you will see plenty of undefined constant errors. + * + * @category Testing + * @package PHPUnit + * @author Scott Mattocks + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.1.0 + */ +class PHPUnit_Skeleton { + /** + * Path to the class file to create a skeleton for. + * @var string + */ + var $classPath; + + /** + * The name of the class + * @var string + */ + var $className; + + /** + * Path to the configuration file needed by class to test. + * @var string + */ + var $configFile; + + /** + * Whether or not to include the methods of the parent class when testing. + * @var boolean + */ + var $includeParents; + + /** + * Whether or not to test private methods. + * @var boolean + */ + var $includePrivate; + + /** + * The test class that will be created. + * @var string + */ + var $testClass; + + /** + * Constructor. Sets the class members and check that the class + * to test is accessible. + * + * @access public + * @param string $className + * @param string $classPath + * @param boolean $includeParents Wheter to include the parent's methods in the test. + * @return void + */ + function PHPUnit_Skeleton($className, $classPath, $includeParents = FALSE, $includePrivate = TRUE) { + // Set up the members. + if (@is_readable($classPath)) { + $this->className = $className; + $this->classPath = $classPath; + } else { + $this->_handleErrors($classPath . ' is not readable. Cannot create test class.'); + } + + // Do we want to include parent methods? + $this->includeParents = $includeParents; + + // Do we want to allow private methods? + $this->includePrivate = $includePrivate; + } + + /** + * The class to test may require a special config file before it can be + * instantiated. This method lets you set that file. + * + * @access public + * @param string $configPath + * @return void + */ + function setConfigFile($configFile) { + // Check that the file is readable + if (@is_readable($configFile)) { + $this->configFile = $configFile; + } else { + $this->_handleErrors($configFile . ' is not readable. Cannot create test class.'); + } + } + + /** + * Create the code that will be the skeleton of the test case. + * + * The test case must have a clss definition, one var, a constructor + * setUp, tearDown, and methods. Optionally and by default the code + * to run the test is added when the class is written to file. + * + * @access public + * @param none + * @return void + */ + function createTestClass() { + // Instantiate the object. + if (isset($this->configFile)) { + require_once $this->configFile; + } + + require_once $this->classPath; + + // Get the methods. + $classMethods = get_class_methods($this->className); + + // Remove the parent methods if needed. + if (!$this->includeParents) { + $parentMethods = get_class_methods(get_parent_class($this->className)); + + if (count($parentMethods)) { + $classMethods = array_diff($classMethods, $parentMethods); + } + } + + // Create the class definition, constructor, setUp and tearDown. + $this->_createDefinition(); + $this->_createConstructor(); + $this->_createSetUpTearDown(); + + if (count($classMethods)) { + // Foreach method create a test case. + foreach ($classMethods as $method) { + // Unless it is the constructor. + if (strcasecmp($this->className, $method) !== 0) { + // Check for private methods. + if (!$this->includePrivate && strpos($method, '_') === 0) { + continue; + } else { + $this->_createMethod($method); + } + } + } + } + + // Finis off the class. + $this->_finishClass(); + } + + /** + * Create the class definition. + * + * The definition consist of a header comment, require statment + * for getting the PHPUnit file, the actual class definition, + * and the definition of the class member variable. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createDefinition() { + // Create header comment. + $this->testClass = + "/**\n" . + " * PHPUnit test case for " . $this->className . "\n" . + " * \n" . + " * The method skeletons below need to be filled in with \n" . + " * real data so that the tests will run correctly. Replace \n" . + " * all EXPECTED_VAL and PARAM strings with real data. \n" . + " * \n" . + " * Created with PHPUnit_Skeleton on " . date('Y-m-d') . "\n" . + " */\n"; + + // Add the require statements. + $this->testClass .= "require_once 'PHPUnit.php';\n"; + + // Add the class definition and variable definition. + $this->testClass .= + "class " . $this->className . "Test extends PHPUnit_TestCase {\n\n" . + " var \$" . $this->className . ";\n\n"; + } + + /** + * Create the class constructor. (PHP4 style) + * + * The constructor simply calls the PHPUnit_TestCase method. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createConstructor() { + // Create the test class constructor. + $this->testClass.= + " function " . $this->className . "Test(\$name)\n" . + " {\n" . + " \$this->PHPUnit_TestCase(\$name);\n" . + " }\n\n"; + } + + /** + * Create setUp and tearDown methods. + * + * The setUp method creates the instance of the object to test. + * The tearDown method releases the instance. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createSetUpTearDown() { + // Create the setUp method. + $this->testClass .= + " function setUp()\n" . + " {\n"; + + if (isset($this->configFile)) { + $this->testClass .= + " require_once '" . $this->configFile . "';\n"; + } + + $this->testClass .= + " require_once '" . $this->classPath . "';\n" . + " \$this->" . $this->className . " =& new " . $this->className . "(PARAM);\n" . + " }\n\n"; + + // Create the tearDown method. + $this->testClass .= + " function tearDown()\n" . + " {\n" . + " unset(\$this->" . $this->className . ");\n" . + " }\n\n"; + } + + /** + * Create a basic skeleton for test methods. + * + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createMethod($methodName) { + // Create a test method. + $this->testClass .= + " function test" . $methodName . "()\n" . + " {\n" . + " \$result = \$this->" . $this->className . "->" . $methodName . "(PARAM);\n" . + " \$expected = EXPECTED_VAL;\n" . + " \$this->assertEquals(\$expected, \$result);\n" . + " }\n\n"; + } + + /** + * Add the closing brace needed for a proper class definition. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _finishClass() { + // Close off the class. + $this->testClass.= "}\n"; + } + + /** + * Create the code that will actually run the test. + * + * This code is added by default so that the test can be run + * just by running the file. To have it not added pass false + * as the second parameter to the writeTestClass method. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createTest() { + // Create a call to the test. + $test = + "// Running the test.\n" . + "\$suite = new PHPUnit_TestSuite('" . $this->className . "Test');\n" . + "\$result = PHPUnit::run(\$suite);\n" . + "echo \$result->toString();\n"; + + return $test; + } + + /** + * Write the test class to file. + * + * This will write the test class created using the createTestClass + * method to a file called Test.php. By default the file + * is written to the current directory and will have code to run + * the test appended to the bottom of the file. + * + * @access public + * @param string $destination The directory to write the file to. + * @param boolean $addTest Wheter to add the test running code. + * @return void + */ + function writeTestClass($destination = './', $addTest = TRUE) { + // Check for something to write to file. + if (!isset($this->testClass)) { + $this->_handleErrors('Noting to write.', PHPUS_WARNING); + return; + } + + // Open the destination file. + $fp = fopen($destination . $this->className . 'Test.php', 'w'); + fwrite($fp, "testClass); + + // Add the call to test the class in the file if we were asked to. + if ($addTest) { + fwrite($fp, $this->_createTest()); + } + + // Close the file. + fwrite($fp, "?>\n"); + fclose($fp); + } + + /** + * Error handler. + * + * This method should be rewritten to use the prefered error + * handling method. (PEAR_ErrorStack) + * + * @access private + * @param string $message The error message. + * @param integer $type An indication of the severity of the error. + * @return void Code may cause PHP to exit. + */ + function _handleErrors($message, $type = E_USER_ERROR) { + // For now just echo the message. + echo $message; + + // Check to see if we should quit. + if ($type == E_USER_ERROR) { + exit; + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestCase.php b/src/tools/pear/src/PHPUnit/TestCase.php new file mode 100644 index 000000000..78a23aa8c --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestCase.php @@ -0,0 +1,293 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestCase.php,v 1.21 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/Assert.php'; +require_once 'PHPUnit/TestResult.php'; + +/** + * A TestCase defines the fixture to run multiple tests. + * + * To define a TestCase + * + * 1) Implement a subclass of PHPUnit_TestCase. + * 2) Define instance variables that store the state of the fixture. + * 3) Initialize the fixture state by overriding setUp(). + * 4) Clean-up after a test by overriding tearDown(). + * + * Each test runs in its own fixture so there can be no side effects + * among test runs. + * + * Here is an example: + * + * + * PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * } + * ?> + * + * + * For each test implement a method which interacts with the fixture. + * Verify the expected results with assertions specified by calling + * assert with a boolean. + * + * + * assertTrue($this->fValue1 + $this->fValue2 == 5); + * } + * ?> + * + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestCase extends PHPUnit_Assert { + /** + * @var boolean + * @access private + */ + var $_failed = FALSE; + + /** + * The name of the test case. + * + * @var string + * @access private + */ + var $_name = ''; + + /** + * PHPUnit_TestResult object + * + * @var object + * @access private + */ + var $_result; + + /** + * Constructs a test case with the given name. + * + * @param string + * @access public + */ + function PHPUnit_TestCase($name = FALSE) { + if ($name !== FALSE) { + $this->setName($name); + } + } + + /** + * Counts the number of test cases executed by run(TestResult result). + * + * @return integer + * @access public + */ + function countTestCases() { + return 1; + } + + /** + * Gets the name of a TestCase. + * + * @return string + * @access public + */ + function getName() { + return $this->_name; + } + + /** + * Runs the test case and collects the results in a given TestResult object. + * + * @param object + * @return object + * @access public + */ + function run(&$result) { + $this->_result = &$result; + $this->_result->run($this); + + return $this->_result; + } + + /** + * Runs the bare test sequence. + * + * @access public + */ + function runBare() { + $this->setUp(); + $this->runTest(); + $this->tearDown(); + $this->pass(); + } + + /** + * Override to run the test and assert its state. + * + * @access protected + */ + function runTest() { + call_user_func( + array( + &$this, + $this->_name + ) + ); + } + + /** + * Sets the name of a TestCase. + * + * @param string + * @access public + */ + function setName($name) { + $this->_name = $name; + } + + /** + * Returns a string representation of the test case. + * + * @return string + * @access public + */ + function toString() { + return ''; + } + + /** + * Creates a default TestResult object. + * + * @return object + * @access protected + */ + function &createResult() { + return new PHPUnit_TestResult; + } + + /** + * Fails a test with the given message. + * + * @param string + * @access protected + */ + function fail($message = '') { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + + if (isset($trace['1']['file'])) { + $message = sprintf( + "%s in %s:%s", + + $message, + $trace['1']['file'], + $trace['1']['line'] + ); + } + } + + $this->_result->addFailure($this, $message); + $this->_failed = TRUE; + } + + /** + * Passes a test. + * + * @access protected + */ + function pass() { + if (!$this->_failed) { + $this->_result->addPassedTest($this); + } + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + * @abstract + */ + function setUp() { /* abstract */ } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + * @abstract + */ + function tearDown() { /* abstract */ } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestDecorator.php b/src/tools/pear/src/PHPUnit/TestDecorator.php new file mode 100644 index 000000000..41332103c --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestDecorator.php @@ -0,0 +1,156 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestDecorator.php,v 1.17 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/TestCase.php'; +require_once 'PHPUnit/TestSuite.php'; + +if (!function_exists('is_a')) { + require_once 'PHP/Compat/Function/is_a.php'; +} + +/** + * A Decorator for Tests. + * + * Use TestDecorator as the base class for defining new + * test decorators. Test decorator subclasses can be introduced + * to add behaviour before or after a test is run. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestDecorator { + /** + * The Test to be decorated. + * + * @var object + * @access protected + */ + var $_test = NULL; + + /** + * Constructor. + * + * @param object + * @access public + */ + function PHPUnit_TestDecorator(&$test) { + if (is_object($test) && + (is_a($test, 'PHPUnit_TestCase') || + is_a($test, 'PHPUnit_TestSuite'))) { + + $this->_test = &$test; + } + } + + /** + * Runs the test and collects the + * result in a TestResult. + * + * @param object + * @access public + */ + function basicRun(&$result) { + $this->_test->run($result); + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + return $this->_test->countTestCases(); + } + + /** + * Returns the test to be run. + * + * @return object + * @access public + */ + function &getTest() { + return $this->_test; + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param object + * @access public + * @abstract + */ + function run(&$result) { /* abstract */ } + + /** + * Returns a string representation of the test. + * + * @return string + * @access public + */ + function toString() { + return $this->_test->toString(); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestFailure.php b/src/tools/pear/src/PHPUnit/TestFailure.php new file mode 100644 index 000000000..7839e4465 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestFailure.php @@ -0,0 +1,130 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestFailure.php,v 1.13 2005/11/10 09:47:14 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +/** + * A TestFailure collects a failed test together with the caught exception. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestFailure { + /** + * @var object + * @access private + */ + var $_failedTest; + + /** + * @var string + * @access private + */ + var $_thrownException; + + /** + * Constructs a TestFailure with the given test and exception. + * + * @param object + * @param string + * @access public + */ + function PHPUnit_TestFailure(&$failedTest, &$thrownException) { + $this->_failedTest = &$failedTest; + $this->_thrownException = &$thrownException; + } + + /** + * Gets the failed test. + * + * @return object + * @access public + */ + function &failedTest() { + return $this->_failedTest; + } + + /** + * Gets the thrown exception. + * + * @return object + * @access public + */ + function &thrownException() { + return $this->_thrownException; + } + + /** + * Returns a short description of the failure. + * + * @return string + * @access public + */ + function toString() { + return sprintf( + "TestCase %s->%s() failed: %s\n", + + get_class($this->_failedTest), + $this->_failedTest->getName(), + $this->_thrownException + ); + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestListener.php b/src/tools/pear/src/PHPUnit/TestListener.php new file mode 100644 index 000000000..9cff52cb2 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestListener.php @@ -0,0 +1,162 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestListener.php,v 1.12 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +/** + * A Listener for test progress. + * + * Here is an example: + * + * + * PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * + * function testAdd() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 4); + * } + * } + * + * class MyListener extends PHPUnit_TestListener { + * function addError(&$test, &$t) { + * print "MyListener::addError() called.\n"; + * } + * + * function addFailure(&$test, &$t) { + * print "MyListener::addFailure() called.\n"; + * } + * + * function endTest(&$test) { + * print "MyListener::endTest() called.\n"; + * } + * + * function startTest(&$test) { + * print "MyListener::startTest() called.\n"; + * } + * } + * + * $suite = new PHPUnit_TestSuite; + * $suite->addTest(new MathTest('testAdd')); + * + * $result = new PHPUnit_TestResult; + * $result->addListener(new MyListener); + * + * $suite->run($result); + * print $result->toString(); + * ?> + * + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestListener { + /** + * An error occurred. + * + * @param object + * @param object + * @access public + * @abstract + */ + function addError(&$test, &$t) { /*abstract */ } + + /** + * A failure occurred. + * + * @param object + * @param object + * @access public + * @abstract + */ + function addFailure(&$test, &$t) { /*abstract */ } + + /** + * A test ended. + * + * @param object + * @access public + * @abstract + */ + function endTest(&$test) { /*abstract */ } + + /** + * A test started. + * + * @param object + * @access public + * @abstract + */ + function startTest(&$test) { /*abstract */ } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestResult.php b/src/tools/pear/src/PHPUnit/TestResult.php new file mode 100644 index 000000000..eb42121e1 --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestResult.php @@ -0,0 +1,347 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestResult.php,v 1.18 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/TestFailure.php'; +require_once 'PHPUnit/TestListener.php'; + +if (!function_exists('is_a')) { + require_once 'PHP/Compat/Function/is_a.php'; +} + +/** + * A TestResult collects the results of executing a test case. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestResult { + /** + * @var array + * @access protected + */ + var $_errors = array(); + + /** + * @var array + * @access protected + */ + var $_failures = array(); + + /** + * @var array + * @access protected + */ + var $_listeners = array(); + + /** + * @var array + * @access protected + */ + var $_passedTests = array(); + + /** + * @var integer + * @access protected + */ + var $_runTests = 0; + + /** + * @var boolean + * @access private + */ + var $_stop = FALSE; + + /** + * Adds an error to the list of errors. + * The passed in exception caused the error. + * + * @param object + * @param object + * @access public + */ + function addError(&$test, &$t) { + $this->_errors[] = new PHPUnit_TestFailure($test, $t); + + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->addError($test, $t); + } + } + + /** + * Adds a failure to the list of failures. + * The passed in exception caused the failure. + * + * @param object + * @param object + * @access public + */ + function addFailure(&$test, &$t) { + $this->_failures[] = new PHPUnit_TestFailure($test, $t); + + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->addFailure($test, $t); + } + } + + /** + * Registers a TestListener. + * + * @param object + * @access public + */ + function addListener(&$listener) { + if (is_object($listener) && + is_a($listener, 'PHPUnit_TestListener')) { + $this->_listeners[] = &$listener; + } + } + + /** + * Adds a passed test to the list of passed tests. + * + * @param object + * @access public + */ + function addPassedTest(&$test) { + $this->_passedTests[] = &$test; + } + + /** + * Informs the result that a test was completed. + * + * @param object + * @access public + */ + function endTest(&$test) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->endTest($test); + } + } + + /** + * Gets the number of detected errors. + * + * @return integer + * @access public + */ + function errorCount() { + return sizeof($this->_errors); + } + + /** + * Returns an Enumeration for the errors. + * + * @return array + * @access public + */ + function &errors() { + return $this->_errors; + } + + /** + * Gets the number of detected failures. + * + * @return integer + * @access public + */ + function failureCount() { + return sizeof($this->_failures); + } + + /** + * Returns an Enumeration for the failures. + * + * @return array + * @access public + */ + function &failures() { + return $this->_failures; + } + + /** + * Returns an Enumeration for the passed tests. + * + * @return array + * @access public + */ + function &passedTests() { + return $this->_passedTests; + } + + /** + * Unregisters a TestListener. + * This requires the Zend Engine 2 (to work properly). + * + * @param object + * @access public + */ + function removeListener(&$listener) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + if ($this->_listeners[$i] === $listener) { + unset($this->_listeners[$i]); + } + } + } + + /** + * Runs a TestCase. + * + * @param object + * @access public + */ + function run(&$test) { + $this->startTest($test); + $this->_runTests++; + $test->runBare(); + $this->endTest($test); + } + + /** + * Gets the number of run tests. + * + * @return integer + * @access public + */ + function runCount() { + return $this->_runTests; + } + + /** + * Checks whether the test run should stop. + * + * @access public + */ + function shouldStop() { + return $this->_stop; + } + + /** + * Informs the result that a test will be started. + * + * @param object + * @access public + */ + function startTest(&$test) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->startTest($test); + } + } + + /** + * Marks that the test run should stop. + * + * @access public + */ + function stop() { + $this->_stop = TRUE; + } + + /** + * Returns a HTML representation of the test result. + * + * @return string + * @access public + */ + function toHTML() { + return '
' . htmlspecialchars($this->toString()) . '
'; + } + + /** + * Returns a text representation of the test result. + * + * @return string + * @access public + */ + function toString() { + $result = ''; + + foreach ($this->_passedTests as $passedTest) { + $result .= sprintf( + "TestCase %s->%s() passed\n", + + get_class($passedTest), + $passedTest->getName() + ); + } + + foreach ($this->_failures as $failedTest) { + $result .= $failedTest->toString(); + } + + return $result; + } + + /** + * Returns whether the entire test was successful or not. + * + * @return boolean + * @access public + */ + function wasSuccessful() { + if (empty($this->_errors) && empty($this->_failures)) { + return TRUE; + } else { + return FALSE; + } + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/PHPUnit/TestSuite.php b/src/tools/pear/src/PHPUnit/TestSuite.php new file mode 100644 index 000000000..c0e069eec --- /dev/null +++ b/src/tools/pear/src/PHPUnit/TestSuite.php @@ -0,0 +1,262 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id: TestSuite.php,v 1.17 2005/11/10 09:47:15 sebastian Exp $ + * @link http://pear.php.net/package/PHPUnit + * @since File available since Release 1.0.0 + */ + +require_once 'PHPUnit/TestCase.php'; + +/** + * A TestSuite is a Composite of Tests. It runs a collection of test cases. + * + * Here is an example using the dynamic test definition. + * + * + * addTest(new MathTest('testPass')); + * ?> + * + * + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass the classname of your TestCase class to the TestSuite + * constructor. + * + * + * + * + * + * This constructor creates a suite with all the methods starting with + * "test" that take no arguments. + * + * @category Testing + * @package PHPUnit + * @author Sebastian Bergmann + * @copyright 2002-2005 Sebastian Bergmann + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PHPUnit + * @since Class available since Release 1.0.0 + */ +class PHPUnit_TestSuite { + /** + * The name of the test suite. + * + * @var string + * @access private + */ + var $_name = ''; + + /** + * The tests in the test suite. + * + * @var array + * @access private + */ + var $_tests = array(); + + /** + * Constructs a TestSuite. + * + * @param mixed + * @access public + */ + function PHPUnit_TestSuite($test = FALSE) { + if ($test !== FALSE) { + $this->setName($test); + $this->addTestSuite($test); + } + } + + /** + * Adds a test to the suite. + * + * @param object + * @access public + */ + function addTest(&$test) { + $this->_tests[] = &$test; + } + + /** + * Adds the tests from the given class to the suite. + * + * @param string + * @access public + */ + function addTestSuite($testClass) { + if (class_exists($testClass)) { + $methods = get_class_methods($testClass); + $parentClasses = array(strtolower($testClass)); + $parentClass = $testClass; + + while(is_string($parentClass = get_parent_class($parentClass))) { + $parentClasses[] = $parentClass; + } + + foreach ($methods as $method) { + if (substr($method, 0, 4) == 'test' && + !in_array($method, $parentClasses)) { + $this->addTest(new $testClass($method)); + } + } + } + } + + /** + * Counts the number of test cases that will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + $count = 0; + + foreach ($this->_tests as $test) { + $count += $test->countTestCases(); + } + + return $count; + } + + /** + * Returns the name of the suite. + * + * @return string + * @access public + */ + function getName() { + return $this->_name; + } + + /** + * Runs the tests and collects their result in a TestResult. + * + * @param object + * @access public + */ + function run(&$result) { + for ($i = 0; $i < sizeof($this->_tests) && !$result->shouldStop(); $i++) { + $this->_tests[$i]->run($result); + } + } + + /** + * Runs a test. + * + * @param object + * @param object + * @access public + */ + function runTest(&$test, &$result) { + $test->run($result); + } + + /** + * Sets the name of the suite. + * + * @param string + * @access public + */ + function setName($name) { + $this->_name = $name; + } + + /** + * Returns the test at the given index. + * + * @param integer + * @return object + * @access public + */ + function &testAt($index) { + if (isset($this->_tests[$index])) { + return $this->_tests[$index]; + } else { + return FALSE; + } + } + + /** + * Returns the number of tests in this suite. + * + * @return integer + * @access public + */ + function testCount() { + return sizeof($this->_tests); + } + + /** + * Returns the tests as an enumeration. + * + * @return array + * @access public + */ + function &tests() { + return $this->_tests; + } + + /** + * Returns a string representation of the test suite. + * + * @return string + * @access public + */ + function toString() { + return ''; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ +?> diff --git a/src/tools/pear/src/VERSIONS.txt b/src/tools/pear/src/VERSIONS.txt index d787e3e6b..175e400e2 100644 --- a/src/tools/pear/src/VERSIONS.txt +++ b/src/tools/pear/src/VERSIONS.txt @@ -1,4 +1,5 @@ Last updated: + - 2010-09-13: PHPUnit added - 2010-08-17: Updated everything to latest version - 2007-02-13: Update DB from 1.7.6 to 1.7.9 @@ -16,3 +17,4 @@ Last updated: * XML_RPC-1.5.4 * XML_Serializer-0.20.0(beta) * XML_Util-1.2.1 +* PHPUnit 1.3.2