Add unit test for base project class
Add unit test for base project class

<?php <?php
/** /**
* Class for a single git project * Class for a single git project
* *
* @author Christopher Han <xiphux@gmail.com> * @author Christopher Han <xiphux@gmail.com>
* @copyright Copyright (c) 2010 Christopher Han * @copyright Copyright (c) 2010 Christopher Han
* @package GitPHP * @package GitPHP
* @subpackage Git\Project * @subpackage Git\Project
*/ */
class GitPHP_Project class GitPHP_Project
{ {
   
/* internal variables {{{1*/ /* internal variables {{{1*/
   
/** /**
* The project root * The project root
* *
* @var string * @var string
*/ */
protected $projectRoot; protected $projectRoot;
   
/** /**
* The project * The project
* *
* @var string * @var string
*/ */
protected $project; protected $project;
   
/* owner internal variables {{{2*/ /* owner internal variables {{{2*/
   
/** /**
* The owner * The owner
* *
* @var string * @var string
*/ */
protected $owner = ""; protected $owner = "";
   
/** /**
* Whether the project owner has been read * Whether the project owner has been read
* *
* @var boolean * @var boolean
*/ */
protected $ownerRead = false; protected $ownerRead = false;
   
/*}}}2*/ /*}}}2*/
   
/* description internal variables {{{2*/ /* description internal variables {{{2*/
   
/** /**
* The description * The description
* *
* @var string * @var string
*/ */
protected $description; protected $description;
   
/** /**
* Whether the description has been read from the file yet * Whether the description has been read from the file yet
* *
* @var boolean * @var boolean
*/ */
protected $readDescription = false; protected $readDescription = false;
   
/*}}}2*/ /*}}}2*/
   
/** /**
* The category * The category
* *
* @var string * @var string
*/ */
protected $category = ''; protected $category = '';
   
/* epoch internal variables {{{2*/ /* epoch internal variables {{{2*/
   
/** /**
* The project epoch * The project epoch
* *
* @var int * @var int
*/ */
protected $epoch; protected $epoch;
   
/** /**
* Whether the project epoch has been read yet * Whether the project epoch has been read yet
* *
* @var boolean * @var boolean
*/ */
protected $epochRead = false; protected $epochRead = false;
   
/*}}}2*/ /*}}}2*/
   
/* HEAD internal variables {{{2*/ /* HEAD internal variables {{{2*/
   
/** /**
* The HEAD hash * The HEAD hash
* *
* @var string * @var string
*/ */
protected $head; protected $head;
   
/** /**
* Whether the head ref has been read yet * Whether the head ref has been read yet
* *
* @var boolean * @var boolean
*/ */
protected $readHeadRef = false; protected $readHeadRef = false;
   
/*}}}*/ /*}}}*/
   
/* ref internal variables {{{2*/ /* ref internal variables {{{2*/
   
/** /**
* The head list for the project * The head list for the project
* *
* @var GitPHP_HeadList * @var GitPHP_HeadList
*/ */
protected $headList; protected $headList;
   
/** /**
* The tag list for the project * The tag list for the project
* *
* @var GitPHP_TagList * @var GitPHP_TagList
*/ */
protected $tagList; protected $tagList;
   
/*}}}2*/ /*}}}2*/
   
/* url internal variables {{{2*/ /* url internal variables {{{2*/
   
/** /**
* The clone url * The clone url
* *
* @var string * @var string
*/ */
protected $cloneUrl = null; protected $cloneUrl = null;
   
/** /**
* The push url * The push url
* *
* @var string * @var string
*/ */
protected $pushUrl = null; protected $pushUrl = null;
   
/*}}}2*/ /*}}}2*/
   
/* bugtracker internal variables {{{2*/ /* bugtracker internal variables {{{2*/
   
/** /**
* The bug url * The bug url
* *
* @var string * @var string
*/ */
protected $bugUrl = null; protected $bugUrl = null;
   
/** /**
* The bug pattern * The bug pattern
* *
* @var string * @var string
*/ */
protected $bugPattern = null; protected $bugPattern = null;
   
/*}}}2*/ /*}}}2*/
   
/** /**
* The website url * The website url
* *
* @var string * @var string
*/ */
protected $website = null; protected $website = null;
   
/** /**
* Stores whether this project is running in compatibility mode * Stores whether this project is running in compatibility mode
* *
* @var boolean * @var boolean
*/ */
protected $compat = false; protected $compat = false;
   
/* hash abbreviation variables {{{2*/ /* hash abbreviation variables {{{2*/
   
/** /**
* The hash abbreviation length * The hash abbreviation length
* *
* @var int * @var int
*/ */
protected $abbreviateLength = null; protected $abbreviateLength = null;
   
/** /**
* Whether hashes should be guaranteed unique * Whether hashes should be guaranteed unique
* *
* @var boolean * @var boolean
*/ */
protected $uniqueAbbreviation = false; protected $uniqueAbbreviation = false;
   
/*}}}2*/ /*}}}2*/
   
/** /**
* The git object manager * The git object manager
* *
* @var GitPHP_GitObjectManager * @var GitPHP_GitObjectManager
*/ */
protected $objectManager; protected $objectManager;
   
/** /**
* Data load strategy * Data load strategy
* *
* @var GitPHP_ProjectLoadStrategy_Interface * @var GitPHP_ProjectLoadStrategy_Interface
*/ */
protected $strategy; protected $strategy;
   
/*}}}1*/ /*}}}1*/
   
/* class methods {{{1*/ /* class methods {{{1*/
   
/** /**
* Class constructor * Class constructor
* *
* @param string $projectRoot project root * @param string $projectRoot project root
* @param string $project project * @param string $project project
* @param GitPHP_ProjectLoadStrategy_Interface $strategy load strategy * @param GitPHP_ProjectLoadStrategy_Interface $strategy load strategy
*/ */
public function __construct($projectRoot, $project, GitPHP_ProjectLoadStrategy_Interface $strategy = null) public function __construct($projectRoot, $project, GitPHP_ProjectLoadStrategy_Interface $strategy = null)
{ {
$this->projectRoot = GitPHP_Util::AddSlash($projectRoot); $this->projectRoot = GitPHP_Util::AddSlash($projectRoot);
$this->SetProject($project); $this->SetProject($project);
   
if ($strategy) if ($strategy)
$this->SetStrategy($strategy); $this->SetStrategy($strategy);
} }
   
/*}}}1*/ /*}}}1*/
   
/* accessors {{{1*/ /* accessors {{{1*/
   
/* project accessors {{{2*/ /* project accessors {{{2*/
   
/** /**
* Gets the project * Gets the project
* *
* @return string the project * @return string the project
*/ */
public function GetProject() public function GetProject()
{ {
return $this->project; return $this->project;
} }
   
/** /**
* Attempts to set the project * Attempts to set the project
* *
* @param string $project the project * @param string $project the project
* @throws Exception if project is invalid or outside of projectroot * @throws Exception if project is invalid or outside of projectroot
*/ */
private function SetProject($project) private function SetProject($project)
{ {
$realProjectRoot = realpath($this->projectRoot); $realProjectRoot = realpath($this->projectRoot);
$path = $this->projectRoot . $project; $path = $this->projectRoot . $project;
$fullPath = realpath($path); $fullPath = realpath($path);
   
if (!is_dir($fullPath)) { if (!is_dir($fullPath)) {
throw new GitPHP_InvalidDirectoryException($fullPath); throw new GitPHP_InvalidDirectoryException($fullPath);
} }
   
if (!is_file($fullPath . '/HEAD')) { if (!is_file($fullPath . '/HEAD')) {
throw new GitPHP_InvalidGitRepositoryException($project); throw new GitPHP_InvalidGitRepositoryException($project);
} }
   
if (preg_match('/(^|\/)\.{0,2}(\/|$)/', $project)) { if (preg_match('/(^|\/)\.{0,2}(\/|$)/', $project)) {
throw new GitPHP_DirectoryTraversalException($project); throw new GitPHP_DirectoryTraversalException($project);
} }
   
$pathPiece = substr($fullPath, 0, strlen($realProjectRoot)); $pathPiece = substr($fullPath, 0, strlen($realProjectRoot));
   
if ((!is_link($path)) && (strcmp($pathPiece, $realProjectRoot) !== 0)) { if ((!is_link($path)) && (strcmp($pathPiece, $realProjectRoot) !== 0)) {
throw new GitPHP_ProjectrootBoundException($project); throw new GitPHP_ProjectrootBoundException($project);
} }
   
$this->project = $project; $this->project = $project;
   
} }
   
/*}}}2*/ /*}}}2*/
   
/** /**
* Gets the project as a filename/url friendly slug * Gets the project as a filename/url friendly slug
* *
* @return string the slug * @return string the slug
*/ */
public function GetSlug() public function GetSlug()
{ {
$project = $this->project; $project = $this->project;
   
if (substr($project, -4) == '.git') if (substr($project, -4) == '.git')
$project = substr($project, 0, -4); $project = substr($project, 0, -4);
return GitPHP_Util::MakeSlug($project); return GitPHP_Util::MakeSlug($project);
} }
   
/** /**
* Gets the full project path * Gets the full project path
* *
* @return string project path * @return string project path
*/ */
public function GetPath() public function GetPath()
{ {
return $this->projectRoot . $this->project; return $this->projectRoot . $this->project;
} }
   
/* owner accessors {{{2 */ /* owner accessors {{{2 */
   
/** /**
* Gets the project's owner * Gets the project's owner
* *
* @return string project owner * @return string project owner
*/ */
public function GetOwner() public function GetOwner()
{ {
if (empty($this->owner) && !$this->ownerRead) { if (empty($this->owner) && !$this->ownerRead) {
$this->ReadOwner(); $this->ReadOwner();
} }
return $this->owner; return $this->owner;
} }
   
/** /**
* Reads the project owner * Reads the project owner
*/ */
protected function ReadOwner() protected function ReadOwner()
{ {
if (empty($this->owner) && function_exists('posix_getpwuid')) { if (empty($this->owner) && function_exists('posix_getpwuid')) {
$uid = fileowner($this->GetPath()); $uid = fileowner($this->GetPath());
if ($uid !== false) { if ($uid !== false) {
$data = posix_getpwuid($uid); $data = posix_getpwuid($uid);
if (isset($data['gecos']) && !empty($data['gecos'])) { if (isset($data['gecos']) && !empty($data['gecos'])) {
$this->owner = $data['gecos']; $this->owner = $data['gecos'];
} elseif (isset($data['name']) && !empty($data['name'])) { } elseif (isset($data['name']) && !empty($data['name'])) {
$this->owner = $data['name']; $this->owner = $data['name'];
} }
} }
} }
   
$this->ownerRead = true; $this->ownerRead = true;
} }
   
/** /**
* Sets the project's owner (from an external source) * Sets the project's owner (from an external source)
* *
* @param string $owner the owner * @param string $owner the owner
*/ */
public function SetOwner($owner) public function SetOwner($owner)
{ {
$this->owner = $owner; $this->owner = $owner;
} }
   
/*}}}2*/ /*}}}2*/
   
/* projectroot accessors {{{2*/ /* projectroot accessors {{{2*/
   
/** /**
* Gets the project root * Gets the project root
* *
* @return string the project root * @return string the project root
*/ */
public function GetProjectRoot() public function GetProjectRoot()
{ {
return $this->projectRoot; return $this->projectRoot;
} }
   
/*}}}2*/ /*}}}2*/
   
/* description accessors {{{2*/ /* description accessors {{{2*/
   
/** /**
* Gets the project description * Gets the project description
* *
* @param $trim length to trim description to (0 for no trim) * @param $trim length to trim description to (0 for no trim)
* @return string project description * @return string project description
*/ */
public function GetDescription($trim = 0) public function GetDescription($trim = 0)
{ {
if (!$this->readDescription) { if (!$this->readDescription) {
if (file_exists($this->GetPath() . '/description')) { if (file_exists($this->GetPath() . '/description')) {
$this->description = file_get_contents($this->GetPath() . '/description'); $this->description = trim(file_get_contents($this->GetPath() . '/description'));
} }
$this->readDescription = true; $this->readDescription = true;
} }
if (($trim > 0) && (strlen($this->description) > $trim)) { if (($trim > 0) && (strlen($this->description) > $trim)) {
return substr($this->description, 0, $trim) . '…'; return substr($this->description, 0, $trim) . '…';
} }
   
return $this->description; return $this->description;
} }
   
/** /**
* Overrides the project description * Overrides the project description
* *
* @param string $descr description * @param string $descr description
*/ */
public function SetDescription($descr) public function SetDescription($descr)
{ {
$this->description = $descr; $this->description = $descr;
$this->readDescription = true; $this->readDescription = true;
} }
   
/*}}}2*/ /*}}}2*/
   
/** /**
* Returns whether gitdaemon is allowed for this project * Returns whether gitdaemon is allowed for this project
* *
* @return boolean git-daemon-export-ok? * @return boolean git-daemon-export-ok?
*/ */
public function GetDaemonEnabled() public function GetDaemonEnabled()
{ {
return file_exists($this->GetPath() . '/git-daemon-export-ok'); return file_exists($this->GetPath() . '/git-daemon-export-ok');
} }
   
/* category accessors {{{2*/ /* category accessors {{{2*/
   
/** /**
* Gets the project's category * Gets the project's category
* *
* @return string category * @return string category
*/ */
public function GetCategory() public function GetCategory()
{ {
if (!empty($this->category)) { if (!empty($this->category)) {
return $this->category; return $this->category;
} }
   
return ''; return '';
} }
   
/** /**
* Sets the project's category * Sets the project's category
* *
* @param string $category category * @param string $category category
*/ */
public function SetCategory($category) public function SetCategory($category)
{ {
$this->category = $category; $this->category = $category;
} }
   
/*}}}2*/ /*}}}2*/
   
/* clone url accessors {{{2*/ /* clone url accessors {{{2*/
   
/** /**
* Gets the clone URL for this repository, if specified * Gets the clone URL for this repository, if specified
* *
* @return string clone url * @return string clone url
*/ */
public function GetCloneUrl() public function GetCloneUrl()
{ {
return $this->cloneUrl; return $this->cloneUrl;
} }
   
/** /**
* Overrides the clone URL for this repository * Overrides the clone URL for this repository
* *
* @param string $cUrl clone url * @param string $cUrl clone url
*/ */
public function SetCloneUrl($cUrl) public function SetCloneUrl($cUrl)
{ {
$this->cloneUrl = $cUrl; $this->cloneUrl = $cUrl;
} }
   
/*}}}2*/ /*}}}2*/
   
/* push url accessors {{{2*/ /* push url accessors {{{2*/
   
/** /**
* Gets the push URL for this repository, if specified * Gets the push URL for this repository, if specified
* *
* @return string push url * @return string push url
*/ */
public function GetPushUrl() public function GetPushUrl()
{ {
return $this->pushUrl; return $this->pushUrl;
} }
   
/** /**
* Overrides the push URL for this repository * Overrides the push URL for this repository
* *
* @param string $pUrl push url * @param string $pUrl push url
*/ */
public function SetPushUrl($pUrl) public function SetPushUrl($pUrl)
{ {
$this->pushUrl = $pUrl; $this->pushUrl = $pUrl;
} }
   
/*}}}2*/ /*}}}2*/
   
/* bugtracker accessors {{{2*/ /* bugtracker accessors {{{2*/
   
/** /**
* Gets the bug URL for this repository, if specified * Gets the bug URL for this repository, if specified
* *
* @return string bug url * @return string bug url
*/ */
public function GetBugUrl() public function GetBugUrl()
{ {
return $this->bugUrl; return $this->bugUrl;
} }
   
/** /**
* Overrides the bug URL for this repository * Overrides the bug URL for this repository
* *
* @param string $bUrl bug url * @param string $bUrl bug url
*/ */
public function SetBugUrl($bUrl) public function SetBugUrl($bUrl)
{ {
$this->bugUrl = $bUrl; $this->bugUrl = $bUrl;
} }
   
/** /**
* Gets the bug pattern for this repository, if specified * Gets the bug pattern for this repository, if specified
* *
* @return string bug pattern * @return string bug pattern
*/ */
public function GetBugPattern() public function GetBugPattern()
{ {
return $this->bugPattern; return $this->bugPattern;
} }
   
/** /**
* Overrides the bug pattern for this repository * Overrides the bug pattern for this repository
* *
* @param string $bPat bug pattern * @param string $bPat bug pattern
*/ */
public function SetBugPattern($bPat) public function SetBugPattern($bPat)
{ {
$this->bugPattern = $bPat; $this->bugPattern = $bPat;
} }
   
/*}}}2*/ /*}}}2*/
   
/* website accessors {{{2*/ /* website accessors {{{2*/
   
/** /**
* Gets the website for this repository, if specified * Gets the website for this repository, if specified
* *
* @return string website * @return string website
*/ */
public function GetWebsite() public function GetWebsite()
{ {
if (!empty($this->website)) { if (!empty($this->website)) {
return $this->website; return $this->website;
} }
   
return null; return null;
} }
   
/** /**
* Sets the website for this repository * Sets the website for this repository
* *
* @param string $site website * @param string $site website
*/ */
public function SetWebsite($site) public function SetWebsite($site)
{ {
$this->website = $site; $this->website = $site;
} }
   
/*}}}2*/ /*}}}2*/
   
/* HEAD accessors {{{2*/ /* HEAD accessors {{{2*/
   
/** /**
* Gets the head commit for this project * Gets the head commit for this project
* *
* Shortcut for getting the tip commit of the HEAD branch * Shortcut for getting the tip commit of the HEAD branch
* *
* @return GitPHP_Commit head commit * @return GitPHP_Commit head commit
*/ */
public function GetHeadCommit() public function GetHeadCommit()
{ {
if (!$this->readHeadRef) if (!$this->readHeadRef)
$this->ReadHeadCommit(); $this->ReadHeadCommit();
   
return $this->GetCommit($this->head); return $this->GetCommit($this->head);
  }
   
  /**
  * Gets the head reference for this project
  *
  * Only returns the raw pointer of the HEAD branch
  *
  * @return string head reference
  */
  public function GetHeadReference()
  {
  if (!$this->readHeadRef)
  $this->ReadHeadCommit();
   
  return $this->head;
} }
   
/** /**
* Reads the head commit hash * Reads the head commit hash
*/ */
public function ReadHeadCommit() public function ReadHeadCommit()
{ {
$this->readHeadRef = true; $this->readHeadRef = true;
   
$this->head = $this->strategy->LoadHead($this); $this->head = $this->strategy->LoadHead($this);
} }
   
/*}}}2*/ /*}}}2*/
   
/* epoch accessors {{{2*/ /* epoch accessors {{{2*/
   
/** /**
* Gets this project's epoch (time of last change) * Gets this project's epoch (time of last change)
* *
* @return integer timestamp * @return integer timestamp
*/ */
public function GetEpoch() public function GetEpoch()
{ {
if (!$this->epochRead) if (!$this->epochRead)
$this->ReadEpoch(); $this->ReadEpoch();
   
return $this->epoch; return $this->epoch;
} }
   
/** /**
* Gets this project's age (time since most recent change) * Gets this project's age (time since most recent change)
* *
* @return integer age * @return integer age
*/ */
public function GetAge() public function GetAge()
{ {
if (!$this->epochRead) if (!$this->epochRead)
$this->ReadEpoch(); $this->ReadEpoch();
   
return time() - $this->epoch; return time() - $this->epoch;
} }
   
/** /**
* Reads this project's epoch (timestamp of most recent change) * Reads this project's epoch (timestamp of most recent change)
*/ */
private function ReadEpoch() private function ReadEpoch()
{ {
$this->epochRead = true; $this->epochRead = true;
   
$this->epoch = $this->strategy->LoadEpoch($this); $this->epoch = $this->strategy->LoadEpoch($this);
} }
   
/*}}}2*/ /*}}}2*/
   
/* compatibility accessors {{{2*/ /* compatibility accessors {{{2*/
   
/** /**
* Gets whether this project is running in compatibility mode * Gets whether this project is running in compatibility mode
* *
* @return boolean true if compatibilty mode * @return boolean true if compatibilty mode
*/ */
public function GetCompat() public function GetCompat()
{ {
return $this->compat; return $this->compat;
} }
   
/** /**
* Sets whether this project is running in compatibility mode * Sets whether this project is running in compatibility mode
* *
* @param boolean true if compatibility mode * @param boolean true if compatibility mode
*/ */
public function SetCompat($compat) public function SetCompat($compat)
{ {
$this->compat = $compat; $this->compat = $compat;
} }
   
/*}}}2*/ /*}}}2*/
   
/** /**
* Set data load strategy * Set data load strategy
* *
* @param GitPHP_ProjectLoadStrategy_Interface $strategy strategy * @param GitPHP_ProjectLoadStrategy_Interface $strategy strategy
*/ */
public function SetStrategy(GitPHP_ProjectLoadStrategy_Interface $strategy) public function SetStrategy(GitPHP_ProjectLoadStrategy_Interface $strategy)
{ {
if (!$strategy) if (!$strategy)
return; return;
   
$this->strategy = $strategy; $this->strategy = $strategy;
} }
   
/*}}}1*/ /*}}}1*/
   
/* data loading methods {{{1*/ /* data loading methods {{{1*/
   
/* commit loading methods {{{2*/ /* commit loading methods {{{2*/
   
/** /**
* Get a commit for this project * Get a commit for this project
* *
* @param string $hash commit hash * @param string $hash commit hash
* @return GitPHP_Commit|null commit object * @return GitPHP_Commit|null commit object
*/ */
public function GetCommit($hash) public function GetCommit($hash)
{ {
if (empty($hash)) if (empty($hash))
return null; return null;
   
if ($hash === 'HEAD') if ($hash === 'HEAD')
return $this->GetHeadCommit(); return $this->GetHeadCommit();
   
if (preg_match('/^[0-9A-Fa-f]{40}$/', $hash)) { if (preg_match('/^[0-9A-Fa-f]{40}$/', $hash)) {
return $this->GetObjectManager()->GetCommit($hash); return $this->GetObjectManager()->GetCommit($hash);
} }
   
if (substr_compare($hash, 'refs/heads/', 0, 11) === 0) { if (substr_compare($hash, 'refs/heads/', 0, 11) === 0) {
$head = substr($hash, 11); $head = substr($hash, 11);
if ($this->GetHeadList()->Exists($head)) if ($this->GetHeadList()->Exists($head))
return $this->GetHeadList()->GetHead($head)->GetCommit(); return $this->GetHeadList()->GetHead($head)->GetCommit();
return null; return null;
} else if (substr_compare($hash, 'refs/tags/', 0, 10) === 0) { } else if (substr_compare($hash, 'refs/tags/', 0, 10) === 0) {
$tag = substr($hash, 10); $tag = substr($hash, 10);
if ($this->GetTagList()->Exists($tag)) { if ($this->GetTagList()->Exists($tag)) {
return $this->GetTagList()->GetTag($tag)->GetCommit(); return $this->GetTagList()->GetTag($tag)->GetCommit();
} }
return null; return null;
} }
   
if ($this->GetHeadList()->Exists($hash)) { if ($this->GetHeadList()->Exists($hash)) {
return $this->GetHeadList()->GetHead($hash)->GetCommit(); return $this->GetHeadList()->GetHead($hash)->GetCommit();
} }
   
if ($this->GetTagList()->Exists($hash)) { if ($this->GetTagList()->Exists($hash)) {
return $this->GetTagList()->GetTag($hash)->GetCommit(); return $this->GetTagList()->GetTag($hash)->GetCommit();
} }
   
if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash)) { if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash)) {
$fullHash = $this->ExpandHash($hash); $fullHash = $this->ExpandHash($hash);
if ($fullHash == $hash) if ($fullHash == $hash)
throw new GitPHP_InvalidHashException($hash); throw new GitPHP_InvalidHashException($hash);
return $this->GetCommit($fullHash); return $this->GetCommit($fullHash);
} }
   
return null; return null;
} }
   
/*}}}2*/ /*}}}2*/
   
/* tag loading methods {{{2*/ /* tag loading methods {{{2*/
   
/** /**
* Gets the tag list * Gets the tag list
* *
* @return GitPHP_TagList tag list * @return GitPHP_TagList tag list
*/ */
public function GetTagList() public function GetTagList()
{ {
return $this->tagList; return $this->tagList;
} }
   
/** /**
* Sets the tag list * Sets the tag list
* *
* @param GitPHP_TagList $tagList tag list * @param GitPHP_TagList $tagList tag list
*/ */
public function SetTagList($tagList) public function SetTagList($tagList)
{ {
if ($tagList && ($tagList->GetProject() !== $this)) if ($tagList && ($tagList->GetProject() !== $this))
throw new Exception('Invalid taglist for this project'); throw new Exception('Invalid taglist for this project');
   
$this->tagList = $tagList; $this->tagList = $tagList;
} }
   
/*}}}2*/ /*}}}2*/
   
/* head loading methods {{{2*/ /* head loading methods {{{2*/
   
/** /**
* Gets the head list * Gets the head list
* *
* @return GitPHP_HeadList head list * @return GitPHP_HeadList head list
*/ */
public function GetHeadList() public function GetHeadList()
{ {
return $this->headList; return $this->headList;
} }
   
/** /**
* Sets the head list * Sets the head list
* *
* @param GitPHP_HeadList $headList head list * @param GitPHP_HeadList $headList head list
*/ */
public function SetHeadList($headList) public function SetHeadList($headList)
{ {
if ($headList && ($headList->GetProject() !== $this)) if ($headList && ($headList->GetProject() !== $this))
throw new Exception('Invalid headlist for this project'); throw new Exception('Invalid headlist for this project');
   
$this->headList = $headList; $this->headList = $headList;
} }
   
/*}}}2*/ /*}}}2*/
   
/* object loader/manager methods {{{2*/ /* object loader/manager methods {{{2*/
   
/** /**
* Get the git object manager for this project * Get the git object manager for this project
* *
* @return GitPHP_GitObjectManager * @return GitPHP_GitObjectManager
*/ */
public function GetObjectManager() public function GetObjectManager()
{ {
return $this->objectManager; return $this->objectManager;
} }
   
/** /**
* Set the git object manager for this project * Set the git object manager for this project
* *
* @param GitPHP_GitObjectManager $objectManager object manager * @param GitPHP_GitObjectManager $objectManager object manager
*/ */
public function SetObjectManager($objectManager) public function SetObjectManager($objectManager)
{ {
if ($objectManager && ($objectManager->GetProject() !== $this)) if ($objectManager && ($objectManager->GetProject() !== $this))
throw new Exception('Invalid object manager for this project'); throw new Exception('Invalid object manager for this project');
   
$this->objectManager = $objectManager; $this->objectManager = $objectManager;
} }
   
/*}}}2*/ /*}}}2*/
   
/* hash management methods {{{2*/ /* hash management methods {{{2*/
   
/** /**
* Gets the hash abbreviation length * Gets the hash abbreviation length
* *
* @return int abbreviate length * @return int abbreviate length
*/ */
public function GetAbbreviateLength() public function GetAbbreviateLength()
{ {
return $this->abbreviateLength; return $this->abbreviateLength;
} }
   
/** /**
* Sets the hash abbreviation length * Sets the hash abbreviation length
* *
* @param int $length abbreviate length * @param int $length abbreviate length
*/ */
public function SetAbbreviateLength($length) public function SetAbbreviateLength($length)
{ {
$this->abbreviateLength = $length; $this->abbreviateLength = $length;
} }
   
/** /**
* Gets whether abbreviated hashes should be guaranteed unique * Gets whether abbreviated hashes should be guaranteed unique
* *
* @return bool true if hashes are guaranteed unique * @return bool true if hashes are guaranteed unique
*/ */
public function GetUniqueAbbreviation() public function GetUniqueAbbreviation()
{ {
return $this->uniqueAbbreviation; return $this->uniqueAbbreviation;
} }
   
/** /**
* Sets whether abbreviated hashes should be guaranteed unique * Sets whether abbreviated hashes should be guaranteed unique
* *
* @param bool true if hashes should be guaranteed unique * @param bool true if hashes should be guaranteed unique
*/ */
public function SetUniqueAbbreviation($unique) public function SetUniqueAbbreviation($unique)
{ {
$this->uniqueAbbreviation = $unique; $this->uniqueAbbreviation = $unique;
} }
   
/** /**
* Calculates the unique abbreviated hash for a full hash * Calculates the unique abbreviated hash for a full hash
* *
* @param string $hash full hash * @param string $hash full hash
* @return string abbreviated hash * @return string abbreviated hash
*/ */
public function AbbreviateHash($hash) public function AbbreviateHash($hash)
{ {
return $this->strategy->AbbreviateHash($this, $hash); return $this->strategy->AbbreviateHash($this, $hash);
} }
   
/** /**
* Finds the full hash for an abbreviated hash * Finds the full hash for an abbreviated hash
* *
* @param string $abbrevHash abbreviated hash * @param string $abbrevHash abbreviated hash
* @return string full hash * @return string full hash
*/ */
public function ExpandHash($abbrevHash) public function ExpandHash($abbrevHash)
{ {
return $this->strategy->ExpandHash($this, $abbrevHash); return $this->strategy->ExpandHash($this, $abbrevHash);
} }
   
/*}}}2*/ /*}}}2*/
   
/*}}}1*/ /*}}}1*/
   
/* static utilities {{{1*/ /* static utilities {{{1*/
   
/** /**
* Compares two projects by project name * Compares two projects by project name
* *
* @param GitPHP_Project $a first project * @param GitPHP_Project $a first project
* @param GitPHP_Project $b second project * @param GitPHP_Project $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareProject($a, $b) public static function CompareProject($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetProject(), $b->GetProject()); return strcmp($a->GetProject(), $b->GetProject());
} }
   
/** /**
* Compares two projects by description * Compares two projects by description
* *
* @param GitPHP_Project $a first project * @param GitPHP_Project $a first project
* @param GitPHP_Project $b second project * @param GitPHP_Project $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareDescription($a, $b) public static function CompareDescription($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetDescription(), $b->GetDescription()); return strcmp($a->GetDescription(), $b->GetDescription());
} }
   
/** /**
* Compares two projects by owner * Compares two projects by owner
* *
* @param GitPHP_Project $a first project * @param GitPHP_Project $a first project
* @param GitPHP_Project $b second project * @param GitPHP_Project $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareOwner($a, $b) public static function CompareOwner($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
return strcmp($a->GetOwner(), $b->GetOwner()); return strcmp($a->GetOwner(), $b->GetOwner());
} }
   
/** /**
* Compares two projects by age * Compares two projects by age
* *
* @param GitPHP_Project $a first project * @param GitPHP_Project $a first project
* @param GitPHP_Project $b second project * @param GitPHP_Project $b second project
* @return integer comparison result * @return integer comparison result
*/ */
public static function CompareAge($a, $b) public static function CompareAge($a, $b)
{ {
$catCmp = strcmp($a->GetCategory(), $b->GetCategory()); $catCmp = strcmp($a->GetCategory(), $b->GetCategory());
if ($catCmp !== 0) if ($catCmp !== 0)
return $catCmp; return $catCmp;
   
if ($a->GetAge() === $b->GetAge()) if ($a->GetAge() === $b->GetAge())
return 0; return 0;
return ($a->GetAge() < $b->GetAge() ? -1 : 1); return ($a->GetAge() < $b->GetAge() ? -1 : 1);
} }
   
/*}}}1*/ /*}}}1*/
   
} }
   
<?php <?php
   
require(dirname(__FILE__) . '/../include/AutoLoader.class.php'); require(dirname(__FILE__) . '/../include/AutoLoader.class.php');
spl_autoload_register(array('GitPHP_AutoLoader', 'AutoLoad')); spl_autoload_register(array('GitPHP_AutoLoader', 'AutoLoad'));
   
define('GITPHP_BASEDIR', dirname(__FILE__) . '/../'); define('GITPHP_BASEDIR', dirname(__FILE__) . '/../');
define('GITPHP_CACHEDIR', GITPHP_BASEDIR . 'cache/'); define('GITPHP_CACHEDIR', GITPHP_BASEDIR . 'cache/');
   
  define('GITPHP_TEST_RESOURCES', dirname(__FILE__) . '/resources');
  define('GITPHP_TEST_PROJECTROOT', GITPHP_TEST_RESOURCES . '/testprojectroot');
   
  <?php
  /**
  * Project test class
  *
  * @author Christopher Han <xiphux@gmail.com>
  * @copyright Copyright (c) 2012 Christopher Han
  * @package GitPHP
  * @subpackage GitPHP\Test\Project
  */
  class GitPHP_ProjectTest extends PHPUnit_Framework_TestCase
  {
  public function testInvalidDirectory()
  {
  $this->setExpectedException('GitPHP_InvalidDirectoryException');
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'nonexistentproject.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  }
 
  public function testInvalidRepo()
  {
  $this->setExpectedException('GitPHP_InvalidGitRepositoryException');
 
  $project = new GitPHP_Project(GITPHP_TEST_RESOURCES, 'testdir', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  }
 
  public function testDirectoryTraversal()
  {
  $this->setExpectedException('GitPHP_DirectoryTraversalException');
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, '../externalrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  }
 
  public function testSlug()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'category/subrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
 
  $this->assertEquals('category-subrepo', $project->GetSlug());
  }
 
  public function testPath()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
 
  $this->assertEquals(GITPHP_TEST_PROJECTROOT . '/testrepo.git', $project->GetPath());
  }
 
  public function testDescription()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
 
  $this->assertEquals('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris tempus commodo libero, ut molestie est molestie vel. Proin molestie sodales elit bibendum aliquam. Vestibulum venenatis purus convallis tortor sodales vel scelerisque justo bibendum. Pellentesque egestas, sapien eu pulvinar suscipit, erat nisi mollis sapien, a lacinia urna lectus nec lectus. Fusce ornare diam a quam faucibus auctor aliquet nunc tincidunt. Sed massa tellus, feugiat eu iaculis id, blandit eget nisi. In suscipit commodo erat, et blandit nisl lacinia non. Sed quis tortor nisl. Phasellus egestas sapien nec elit tempor a tempor lectus tincidunt.', $project->GetDescription());
  $this->assertEquals('Lorem ipsum dolor si…', $project->GetDescription(20));
  }
 
  public function testDaemonEnabled()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $this->assertFalse($project->GetDaemonEnabled());
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $this->assertTrue($project->GetDaemonEnabled());
  }
 
  public function testHead()
  {
  $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock->expects($this->once())->method('LoadHead')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('refs/heads/master'));
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock);
  $this->assertEquals('refs/heads/master', $project->GetHeadReference());
  }
 
  public function testEpoch()
  {
  $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock->expects($this->once())->method('LoadEpoch')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('12345678'));
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock);
  $this->assertEquals('12345678', $project->GetEpoch());
  }
 
  public function testAbbreviateHash()
  {
  $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock->expects($this->once())->method('AbbreviateHash')->with($this->isInstanceOf('GitPHP_Project'), $this->equalTo('longhash'))->will($this->returnValue('shorthash'));
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock);
  $this->assertEquals('shorthash', $project->AbbreviateHash('longhash'));
  }
 
  public function testExpandHash()
  {
  $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock->expects($this->once())->method('ExpandHash')->with($this->isInstanceOf('GitPHP_Project'), $this->equalTo('shorthash'))->will($this->returnValue('longhash'));
 
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock);
  $this->assertEquals('longhash', $project->ExpandHash('shorthash'));
  }
 
  public function testCompareProject()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $project2 = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
 
  $this->assertEquals(0, GitPHP_Project::CompareProject($project, $project));
  $this->assertLessThan(0, GitPHP_Project::CompareProject($project, $project2));
  $this->assertGreaterThan(0, GitPHP_Project::CompareProject($project2, $project));
 
  $project->SetCategory('b');
  $this->assertEquals(0, GitPHP_Project::CompareProject($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareProject($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareProject($project2, $project));
 
  $project2->SetCategory('a');
  $this->assertEquals(0, GitPHP_Project::CompareProject($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareProject($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareProject($project2, $project));
  }
 
  public function testCompareDescription()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $project->SetDescription('A description');
  $project2 = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $project->SetDescription('B description');
 
  $this->assertEquals(0, GitPHP_Project::CompareDescription($project, $project));
  $this->assertLessThan(0, GitPHP_Project::CompareDescription($project, $project2));
  $this->assertGreaterThan(0, GitPHP_Project::CompareDescription($project2, $project));
 
  $project->SetCategory('b');
  $this->assertEquals(0, GitPHP_Project::CompareDescription($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareDescription($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareDescription($project2, $project));
 
  $project2->SetCategory('a');
  $this->assertEquals(0, GitPHP_Project::CompareDescription($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareDescription($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareDescription($project2, $project));
  }
 
  public function testCompareOwner()
  {
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $project->SetOwner('A owner');
  $project2 = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $this->getMock('GitPHP_ProjectLoadStrategy_Interface'));
  $project->SetOwner('B owner');
 
  $this->assertEquals(0, GitPHP_Project::CompareOwner($project, $project));
  $this->assertLessThan(0, GitPHP_Project::CompareOwner($project, $project2));
  $this->assertGreaterThan(0, GitPHP_Project::CompareOwner($project2, $project));
 
  $project->SetCategory('b');
  $this->assertEquals(0, GitPHP_Project::CompareOwner($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareOwner($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareOwner($project2, $project));
 
  $project2->SetCategory('a');
  $this->assertEquals(0, GitPHP_Project::CompareOwner($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareOwner($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareOwner($project2, $project));
  }
 
  public function testCompareAge()
  {
  $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock->expects($this->once())->method('LoadEpoch')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('2'));
  $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $strategymock);
 
  $strategymock2 = $this->getMock('GitPHP_ProjectLoadStrategy_Interface');
  $strategymock2->expects($this->once())->method('LoadEpoch')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('1'));
  $project2 = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock2);
 
  $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project));
  $this->assertLessThan(0, GitPHP_Project::CompareAge($project, $project2));
  $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project2, $project));
 
  $project->SetCategory('b');
  $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareAge($project2, $project));
 
  $project2->SetCategory('a');
  $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project));
  $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project, $project2));
  $this->assertLessThan(0, GitPHP_Project::CompareAge($project2, $project));
  }
 
  }
 
  ref: refs/heads/master
 
  ref: refs/heads/master
 
  ref: refs/heads/master
 
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris tempus commodo libero, ut molestie est molestie vel. Proin molestie sodales elit bibendum aliquam. Vestibulum venenatis purus convallis tortor sodales vel scelerisque justo bibendum. Pellentesque egestas, sapien eu pulvinar suscipit, erat nisi mollis sapien, a lacinia urna lectus nec lectus. Fusce ornare diam a quam faucibus auctor aliquet nunc tincidunt. Sed massa tellus, feugiat eu iaculis id, blandit eget nisi. In suscipit commodo erat, et blandit nisl lacinia non. Sed quis tortor nisl. Phasellus egestas sapien nec elit tempor a tempor lectus tincidunt.
 
  ref: refs/heads/master
 
comments