Skip to content

Commit 0e5d5f1

Browse files
harm-lessharm-less
authored andcommitted
Tests added for requirements
A few tests have been added and some logic has been resived
1 parent 20b32cd commit 0e5d5f1

File tree

14 files changed

+439
-56
lines changed

14 files changed

+439
-56
lines changed

samples/FQ/Samples/Simple.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
use FQ\Dirs\ChildDir;
66
use FQ\Dirs\RootDir;
7-
use FQ\Query\FilesQuery;
87
use FQ\Query\FilesQueryBuilder;
9-
use FQ\Query\Selection\ChildSelection;
108

119
class Simple extends SampleBootstrapper {
1210

@@ -24,13 +22,10 @@ public function queryFile1FromChild1() {
2422

2523

2624
$builder = new FilesQueryBuilder($this);
27-
$builder->includeChildDirs('child1')->fileName('File1');
28-
25+
$builder->excludeRootDirs('root1')->includeChildDirs('child1')->fileName('File1');
2926

3027
$query = $builder->run();
3128

32-
//pr($builder);
33-
3429
return $query->listPaths();
3530
}
3631

samples/FQ/Samples/simple/root1/child1/File2.php

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace FQ\Exceptions;
4+
5+
class FileQueryRequirementsException extends FileQueryException
6+
{
7+
}

src/FQ/query/FilesQuery.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class FilesQuery {
3636
*/
3737
private $_currentQueryChildren;
3838

39+
/**
40+
* @var RootDir[]
41+
*/
42+
private $_cachedQueryRootDirs;
43+
3944
/**
4045
* @var bool Indicator if the query has run or not
4146
*/
@@ -78,6 +83,7 @@ function __construct(Files $files) {
7883
}
7984

8085
public function reset() {
86+
$this->_cachedQueryRootDirs = null;
8187
$this->_currentQueryChildren = array();
8288

8389
$this->requirements()->removeAll();
@@ -185,10 +191,11 @@ protected function _hasRun() {
185191
*/
186192
public function run($fileName) {
187193
$this->_queriedFileName = $fileName;
194+
$rootDirsSelection = $this->_getCachedRootDirSelection();
195+
188196
$this->_currentQueryChildren = array();
189197
foreach ($this->getCurrentChildDirSelection() as $childDir) {
190-
pr($childDir);
191-
$this->_currentQueryChildren[$childDir->id()] = $this->processQueryChild($childDir);
198+
$this->_currentQueryChildren[$childDir->id()] = $this->processQueryChild($childDir, $rootDirsSelection);
192199
}
193200
$this->_hasRun = true;
194201
return $this->listPaths();
@@ -198,19 +205,27 @@ public function run($fileName) {
198205
* @return RootDir[]
199206
*/
200207
public function getCurrentRootDirSelection() {
201-
return $this->_rootDirSelection->getSelection($this->files()->rootDirs());
208+
return $this->getRootDirSelection()->getSelection($this->files()->rootDirs());
202209
}
203210

204211
/**
205212
* @return ChildDir[]
206213
*/
207214
public function getCurrentChildDirSelection() {
208-
return $this->_childDirSelection->getSelection($this->files()->childDirs());
215+
return $this->getChildDirSelection()->getSelection($this->files()->childDirs());
216+
}
217+
218+
protected function _getCachedRootDirSelection() {
219+
if ($this->_cachedQueryRootDirs === null) {
220+
$this->_cachedQueryRootDirs = $this->getCurrentRootDirSelection();
221+
}
222+
return $this->_cachedQueryRootDirs;
209223
}
210224

211-
protected function processQueryChild(ChildDir $childDir) {
225+
protected function processQueryChild(ChildDir $childDir, $rootSelection) {
212226
$queryChild = $this->_getQueryChild($childDir);
213227
$queryChild->reset();
228+
$queryChild->setRootDirs($rootSelection);
214229
if (!$this->requirements()->meetsRequirements($queryChild)) {
215230
return false;
216231
}

src/FQ/query/FilesQueryChild.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace FQ\Query;
44

55
use FQ\Dirs\ChildDir;
6+
use FQ\Dirs\RootDir;
67
use FQ\Exceptions\FileQueryException;
78
use FQ\Files;
89
use FQ\Query\Selection\RootSelection;
@@ -14,6 +15,11 @@ class FilesQueryChild {
1415
*/
1516
private $_filesQuery;
1617

18+
/**
19+
* @var RootDir[]
20+
*/
21+
private $_rootDirs;
22+
1723
/**
1824
* @var ChildDir
1925
*/
@@ -59,6 +65,16 @@ function __construct(FilesQuery $filesQuery, ChildDir $childDir) {
5965
$this->_childDir = $childDir;
6066
}
6167

68+
public function setRootDirs($dirs) {
69+
$this->_rootDirs = $dirs;
70+
}
71+
public function getRootDirs() {
72+
if ($this->_rootDirs === null) {
73+
return array();
74+
}
75+
return $this->_rootDirs;
76+
}
77+
6278
/**
6379
* Resets the FilesQueryChild so it can be reused
6480
*/
@@ -67,6 +83,8 @@ public function reset() {
6783
$this->_rawAbsolutePaths = null;
6884
$this->_rawBasePaths = null;
6985

86+
$this->_rootDirs = null;
87+
7088
$this->_pathsExist = null;
7189

7290
$this->_filteredPathsCashed = null;
@@ -150,7 +168,8 @@ public function rawBasePaths() {
150168
private function _generatePaths($dirMethod) {
151169
$paths = array();
152170
$methodExists = null;
153-
foreach ($this->files()->rootDirs() as $rootDir) {
171+
172+
foreach ($this->getRootDirs() as $rootDir) {
154173
if ($methodExists === null) {
155174
$methodExists = method_exists($rootDir, $dirMethod);
156175
if (!$methodExists) {
@@ -228,7 +247,7 @@ private function _cachedFilterPaths() {
228247
if (empty($this->_filteredPathsCashed)) {
229248
$filters = $this->query()->filters();
230249

231-
$rootDirs = $this->files()->rootDirs();
250+
$rootDirs = $this->getRootDirs();
232251
$pathsExist = $this->pathsExist();
233252

234253
$filteredPaths = array();

src/FQ/query/FilesQueryRequirements.php

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace FQ\Query;
44

5-
use FQ\Exceptions\FileQueryException;
65
use FQ\Exceptions\FileQueryRequirementsException;
76

87
class FilesQueryRequirements {
@@ -25,6 +24,8 @@ class FilesQueryRequirements {
2524
const LEVELS_ALL = 'levels_all';
2625

2726
function __construct() {
27+
$this->_requirements = array();
28+
2829
$this->registerRequirement(self::LEVELS_ONE, array($this, 'requirementAtLeastOne'));
2930
$this->registerRequirement(self::LEVELS_LAST, array($this, 'requirementLast'));
3031
$this->registerRequirement(self::LEVELS_ALL, array($this, 'requirementAll'));
@@ -49,15 +50,15 @@ public function addRequirements($requirements) {
4950

5051
/**
5152
* @param string|int $requirement
52-
* @throws FileQueryException Thrown when there provided requirement is neither a string or an integer
53+
* @throws FileQueryRequirementsException Thrown when there provided requirement is neither a string or an integer
5354
* @return bool Return true when added. Returns false when it was already part of the requirements
5455
*/
5556
public function addRequirement($requirement) {
56-
if (!is_string($requirement) || !is_int($requirement)) {
57-
throw new FileQueryException(sprintf('A requirement van only be of type integer or string. Provided requirement is of type "%s"', gettype($requirement)));
57+
if (!(is_string($requirement) || is_int($requirement))) {
58+
throw new FileQueryRequirementsException(sprintf('A requirement van only be of type integer or string. Provided requirement is of type "%s"', gettype($requirement)));
5859
}
5960
if (!$this->requirementIsRegistered($requirement)) {
60-
throw new FileQueryException(sprintf('Trying to add a requirement, but it isn\'t registered. Provided requirement "%s"', $requirement));
61+
throw new FileQueryRequirementsException(sprintf('Trying to add a requirement, but it isn\'t registered. Provided requirement "%s"', $requirement));
6162
}
6263
if (!$this->hasRequirement($requirement)) {
6364
$this->_requirements[] = $requirement;
@@ -101,8 +102,17 @@ public function hasRequirement($requirement) {
101102
* @return bool Returns true if there is at least one requirement, otherwise it will return false
102103
*/
103104
public function hasRequirements() {
105+
return $this->countRequirements() !== 0;
106+
}
107+
108+
/**
109+
* Count all configured requirements.
110+
*
111+
* @return int Returns the total number of requirements
112+
*/
113+
public function countRequirements() {
104114
$requirements = $this->requirements();
105-
return count($requirements) !== 0;
115+
return count($requirements);
106116
}
107117

108118
/**
@@ -120,56 +130,91 @@ public function requirementIsRegistered($requirement) {
120130
* @throws FileQueryRequirementsException
121131
*/
122132
public function registerRequirement($id, $callable) {
123-
if (!is_callable($callable, true)) {
124-
throw new FileQueryRequirementsException(sprintf('Trying to register a requirement but the requirement isn\'t callable. Info "%s"', implode(', ', (array) $callable)));
133+
if (is_string($callable) && !method_exists($this, $callable)) {
134+
throw new FileQueryRequirementsException(sprintf('Trying to register a requirement via a string but the requirement isn\'t callable. Method name "%s"', $callable));
135+
}
136+
else if (is_array($callable)) {
137+
$class = new \ReflectionClass($callable[0]);
138+
if (!$class->hasMethod($callable[1])) {
139+
throw new FileQueryRequirementsException(sprintf('Trying to register a requirement but the requirement isn\'t callable. Class name "%s", method name "%s"', get_class($callable[0]), $callable[1]));
140+
}
141+
}
142+
else {
143+
throw new FileQueryRequirementsException(sprintf('Trying to register a requirement but the requirement\'s callable isn\'t a known data-type. Must be a string or an array. Type given "%s"', gettype($callable)));
144+
}
145+
146+
if (isset($this->_registeredRequirements[$id])) {
147+
return false;
125148
}
126149
$this->_registeredRequirements[$id] = $callable;
127150
return true;
128151
}
129152

153+
/**
154+
* Count all registered requirements.
155+
*
156+
* @return int Returns the total number of registered requirements
157+
*/
158+
public function countRegisteredRequirements() {
159+
return count($this->_registeredRequirements);
160+
}
161+
162+
/**
163+
* Check whether a requirements has already been registered
164+
* @param string $id ID of the requirement
165+
* @return bool Return true if the requirement is already registered
166+
*/
167+
public function isRegisteredRequirement($id) {
168+
return isset($this->_registeredRequirements[$id]);
169+
}
170+
130171
/**
131172
* @param string $id
132173
* @param FilesQueryChild $child
133-
* @throws FileQueryException
174+
* @throws FileQueryRequirementsException
134175
* @return mixed
135176
*/
136177
public function tryRequirement($id, FilesQueryChild $child) {
137-
if ($this->requirementIsRegistered($id)) {
138-
throw new FileQueryException(sprintf('Trying to call a requirement, but it isn\'t registered. Provided requirement "%s"', $id), 10);
178+
if (!$this->requirementIsRegistered($id)) {
179+
throw new FileQueryRequirementsException(sprintf('Trying to call a requirement, but it isn\'t registered. Provided requirement "%s"', $id), 10);
139180
}
140181
return call_user_func($this->_registeredRequirements[$id], $child);
141182
}
142183

143184
/**
144185
* @param FilesQueryChild $child
145-
* @return bool|FileQueryException
186+
* @return bool|FileQueryRequirementsException
146187
*/
147188
protected function requirementAtLeastOne(FilesQueryChild $child) {
148-
if ($child->totalExistingPaths() === 0) {
189+
if (!$child->totalExistingPaths() >= 1) {
149190
return new FileQueryRequirementsException(sprintf('At least 1 file must be available for file "%s" in child with an id of "%s". Please create the file in any of these locations: %s', $child->relativePath(), $child->childDir()->id(), implode($child->rawAbsolutePaths())));
150191
}
151192
return true;
152193
}
153194

154195
/**
155196
* @param FilesQueryChild $child
156-
* @return bool|FileQueryException
197+
* @return bool|FileQueryRequirementsException
157198
*/
158199
protected function requirementLast(FilesQueryChild $child) {
159-
$pathsExist = $child->pathsExist();
160-
if ($child->totalExistingPaths() === 0 || $pathsExist[0] == null) {
161-
return new FileQueryException(sprintf('Last file "%s" not found in child "%s" but it is required', $child->relativePath(), $child->childDir()->id()));
200+
$pathsExist = array_reverse($child->pathsExist());
201+
foreach ($pathsExist as $rootDir) {
202+
if ($rootDir === false) {
203+
return new FileQueryRequirementsException(sprintf('Last file "%s" not found in child "%s" but it is required', $child->relativePath(), $child->childDir()->id()));
204+
}
205+
// just check the first root dir (which is the last one because it was reversed)
206+
break;
162207
}
163208
return true;
164209
}
165210

166211
/**
167212
* @param FilesQueryChild $child
168-
* @return bool|FileQueryException
213+
* @return bool|FileQueryRequirementsException
169214
*/
170215
protected function requirementAll(FilesQueryChild $child) {
171-
if ($child->totalExistingPaths() != $child->files()->totalRootDirs()) {
172-
return new FileQueryException(sprintf('All "%s" children must contain a file called "%s".', $child->childDir()->id(), $child->relativePath()));
216+
if ($child->totalExistingPaths() != count($child->getRootDirs())) {
217+
return new FileQueryRequirementsException(sprintf('All "%s" children must contain a file called "%s".', $child->childDir()->id(), $child->relativePath()));
173218
}
174219
return true;
175220
}
@@ -179,8 +224,10 @@ protected function requirementAll(FilesQueryChild $child) {
179224
*
180225
* @param FilesQueryChild $queryChild
181226
* @param bool $throwExceptionOnFail
182-
* @throws \Exception
183-
* @return mixed Returns true if all requirements are met. Otherwise returns an un-thrown exception if 'throwExceptionOnFail' is set to false or the response from the requirement
227+
* @throws \Exception When $throwExceptionOnFail is set to true and one of the requirements fails, it will throw
228+
* the exception from that fail. Otherwise this exception will be returned
229+
* @return mixed Returns true if all requirements are met. Otherwise returns an un-thrown exception
230+
* if 'throwExceptionOnFail' is set to false or the response from the requirement
184231
*/
185232
public function meetsRequirements(FilesQueryChild $queryChild, $throwExceptionOnFail = true) {
186233
// if there are no requirements it certainly is valid and it can be returned immediately

tests/FQ/Tests/AbstractFQTest.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ abstract class AbstractFQTest extends PHPUnit_Framework_TestCase
2626

2727
const DIR_ABSOLUTE_DEFAULT = __DIR__;
2828
const DIR_CUSTOM_ID = 'custom_id';
29-
const ROOT_DIR_ABSOLUTE_DEFAULT = __DIR__;
29+
30+
const ROOT_DIR_DEFAULT_ID = ACTUAL_ROOT_DIR_FIRST_ID;
31+
const ROOT_DIR_DEFAULT_ABSOLUTE_PATH = ACTUAL_ROOT_DIR_FIRST_ABSOLUTE_PATH;
32+
const ROOT_DIR_SECOND_ID = ACTUAL_ROOT_DIR_SECOND_ID;
33+
const ROOT_DIR_SECOND_ABSOLUTE_PATH = ACTUAL_ROOT_DIR_SECOND_ABSOLUTE_PATH;
34+
3035
const ROOT_DIR_ID_CUSTOM = 'rootDir';
31-
const CHILD_DIR_DEFAULT = 'child';
36+
const CHILD_DIR_DEFAULT = ACTUAL_CHILD_DIR;
3237

3338

3439
/**
@@ -60,7 +65,11 @@ protected function callObjectWithNonPublicMethod($obj, $name, $args) {
6065
$method->setAccessible(true);
6166

6267
$args = is_array($args) ? $args : (array) $args;
63-
return $method->invokeArgs($obj, $args);
68+
$result = $method->invokeArgs($obj, $args);
69+
if (is_a($result, 'Exception')) {
70+
throw $result;
71+
}
72+
return $result;
6473
}
6574

6675
protected function __newDir($id = self::DIR_CUSTOM_ID, $dir = self::DIR_ABSOLUTE_DEFAULT, $required = false) {
@@ -73,11 +82,14 @@ protected function _newFictitiousDir($required = true) {
7382
return $this->__newDir('does_not_exist', $required);
7483
}
7584

76-
protected function __newRootDir($id = self::ROOT_DIR_ID_CUSTOM, $absoluteDir = self::ROOT_DIR_ABSOLUTE_DEFAULT, $basePath = null, $required = false) {
85+
protected function __newRootDir($id = self::ROOT_DIR_ID_CUSTOM, $absoluteDir = self::ROOT_DIR_DEFAULT_ABSOLUTE_PATH, $basePath = null, $required = false) {
7786
return new RootDir($id, $absoluteDir, $basePath, $required);
7887
}
7988
protected function _newActualRootDir($basePath = null, $required = false) {
80-
return $this->__newRootDir(self::ROOT_DIR_ID_CUSTOM, self::ROOT_DIR_ABSOLUTE_DEFAULT, $basePath, $required);
89+
return $this->__newRootDir(self::ROOT_DIR_DEFAULT_ID, self::ROOT_DIR_DEFAULT_ABSOLUTE_PATH, $basePath, $required);
90+
}
91+
protected function _newActualRootDirSecond($basePath = null, $required = false) {
92+
return $this->__newRootDir(self::ROOT_DIR_SECOND_ID, self::ROOT_DIR_SECOND_ABSOLUTE_PATH, $basePath, $required);
8193
}
8294
protected function _newFictitiousRootDir($required = true) {
8395
return $this->__newRootDir('does_not_exist', 'does_not_exist', $required);

0 commit comments

Comments
 (0)