1
+ <?php
2
+ declare (strict_types=1 );
3
+
4
+ namespace MaplePHP \Unitary ;
5
+
6
+ use Closure ;
7
+ use RuntimeException ;
8
+ use MaplePHP \Blunder \Handlers \CliHandler ;
9
+ use MaplePHP \Blunder \Run ;
10
+ use RecursiveDirectoryIterator ;
11
+ use RecursiveIteratorIterator ;
12
+
13
+ class FileIterator
14
+ {
15
+ const PATTERN = 'unitary-*.php ' ;
16
+
17
+ private array $ args ;
18
+
19
+ public function __construct (array $ args = [])
20
+ {
21
+ $ this ->args = $ args ;
22
+ }
23
+
24
+ /**
25
+ * Will Execute all unitary test files.
26
+ * @param string $directory
27
+ * @return void
28
+ * @throws RuntimeException
29
+ */
30
+ public function executeAll (string $ directory ): void
31
+ {
32
+ $ files = $ this ->findFiles ($ directory );
33
+ if (empty ($ files )) {
34
+ throw new RuntimeException ("No files found matching the pattern \"" . static ::PATTERN . "\" in directory \"$ directory \" " );
35
+ } else {
36
+ foreach ($ files as $ file ) {
37
+ extract ($ this ->args , EXTR_PREFIX_SAME , "wddx " );
38
+ Unit::resetUnit ();
39
+ Unit::setHeaders ([
40
+ "args " => $ this ->args ,
41
+ "file " => $ file ,
42
+ "checksum " => md5 ($ file )
43
+ ]);
44
+
45
+ $ this ->requireUnitFile ($ file )();
46
+ if (!Unit::hasUnit ()) {
47
+ throw new RuntimeException ("The Unitary Unit class has not been initiated inside \"$ file \". " );
48
+ }
49
+ }
50
+
51
+ Unit::completed ();
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Will Scan and find all unitary test files
57
+ * @param $dir
58
+ * @return array
59
+ */
60
+ private function findFiles ($ dir ): array
61
+ {
62
+ $ files = [];
63
+ $ realDir = realpath ($ dir );
64
+ if (!$ realDir ) {
65
+ throw new RuntimeException ("Directory \"$ dir \" does not exist. Try using a absolut path! " );
66
+ }
67
+ $ iterator = new RecursiveIteratorIterator (new RecursiveDirectoryIterator ($ dir ));
68
+ foreach ($ iterator as $ file ) {
69
+ if (fnmatch (static ::PATTERN , $ file ->getFilename ()) &&
70
+ (isset ($ this ->args ['path ' ]) || !str_contains ($ file ->getPathname (), DIRECTORY_SEPARATOR . "vendor " . DIRECTORY_SEPARATOR ))) {
71
+ if (!$ this ->findExcluded ($ this ->exclude (), $ dir , $ file ->getPathname ())) {
72
+ $ files [] = $ file ->getPathname ();
73
+ }
74
+ }
75
+ }
76
+ return $ files ;
77
+ }
78
+
79
+ /**
80
+ * Get exclude parameter
81
+ * @return array
82
+ */
83
+ function exclude (): array
84
+ {
85
+ $ excl = array ();
86
+ if (isset ($ this ->args ['exclude ' ])) {
87
+ $ exclude = explode (', ' , $ this ->args ['exclude ' ]);
88
+ foreach ($ exclude as $ file ) {
89
+ $ file = str_replace (['" ' , "' " ], "" , $ file );
90
+ $ new = trim ($ file );
91
+ $ lastChar = substr ($ new , -1 );
92
+ if ($ lastChar === DIRECTORY_SEPARATOR ) {
93
+ $ new .= "* " ;
94
+ }
95
+ $ excl [] = trim ($ new );
96
+ }
97
+ }
98
+ return $ excl ;
99
+ }
100
+
101
+ /**
102
+ * Validate a exclude path
103
+ * @param array $exclArr
104
+ * @param string $relativeDir
105
+ * @param string $file
106
+ * @return bool
107
+ */
108
+ function findExcluded (array $ exclArr , string $ relativeDir , string $ file ): bool
109
+ {
110
+ $ file = $ this ->getNaturalPath ($ file );
111
+ foreach ($ exclArr as $ excl ) {
112
+ $ relativeExclPath = $ this ->getNaturalPath ($ relativeDir . DIRECTORY_SEPARATOR . $ excl );
113
+ if (fnmatch ($ relativeExclPath , $ file )) {
114
+ return true ;
115
+ }
116
+ }
117
+ return false ;
118
+ }
119
+
120
+ /**
121
+ * Get path as natural path
122
+ * @param string $path
123
+ * @return string
124
+ */
125
+ function getNaturalPath (string $ path ): string
126
+ {
127
+ return str_replace ("\\" , "/ " , $ path );
128
+ }
129
+
130
+ /**
131
+ * Require file without inheriting any class information
132
+ * @param string $file
133
+ * @return Closure
134
+ */
135
+ private function requireUnitFile (string $ file ): Closure
136
+ {
137
+ $ call = function () use ($ file ): void
138
+ {
139
+
140
+ $ cli = new CliHandler ();
141
+ if (isset (self ::$ headers ['args ' ]['trace ' ])) {
142
+ $ cli ->enableTraceLines (true );
143
+ }
144
+ $ run = new Run ($ cli );
145
+ $ run ->load ();
146
+
147
+ ob_start ();
148
+ require_once ($ file );
149
+ Unit::getUnit ()->execute ();
150
+
151
+ $ outputBuffer = ob_get_clean ();
152
+ if ($ outputBuffer && Unit::hasUnit ()) {
153
+ Unit::getUnit ()->buildNotice ("Note: " , $ outputBuffer , 80 );
154
+ }
155
+ };
156
+ return $ call ->bindTo (null );
157
+ }
158
+ }
0 commit comments