• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

donatj / mock-webserver / 15544212778

09 Jun 2025 08:42PM UTC coverage: 78.841% (-1.4%) from 80.24%
15544212778

push

github

web-flow
Merge pull request #61 from donatj/feature/phpstan

Add phpstan to ci

5 of 12 new or added lines in 4 files covered. (41.67%)

1 existing line in 1 file now uncovered.

272 of 345 relevant lines covered (78.84%)

4.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.16
/src/InternalServer.php
1
<?php
2

3
namespace donatj\MockWebServer;
4

5
use donatj\MockWebServer\Exceptions\ServerException;
6
use donatj\MockWebServer\Responses\DefaultResponse;
7
use donatj\MockWebServer\Responses\NotFoundResponse;
8

9
/**
10
 * Class InternalServer
11
 *
12
 * @internal
13
 */
14
class InternalServer {
15

16
        /** @var string */
17
        private $tmpPath;
18
        /** @var \donatj\MockWebServer\RequestInfo */
19
        private $request;
20
        /** @var callable */
21
        private $header;
22
        /** @var callable */
23
        private $httpResponseCode;
24

25
        private const DEFAULT_REF = 'default';
26

27
        public function __construct(
28
                string $tmpPath,
29
                RequestInfo $request,
30
                ?callable $header = null,
31
                ?callable $httpResponseCode = null
32
        ) {
33
                if( $header === null ) {
8✔
34
                        $header = "\\header";
1✔
35
                }
36

37
                if( $httpResponseCode === null ) {
8✔
38
                        $httpResponseCode = "\\http_response_code";
1✔
39
                }
40

41
                $this->tmpPath = $tmpPath;
8✔
42

43
                $count = self::incrementRequestCounter($this->tmpPath);
8✔
44
                $this->logRequest($request, $count);
8✔
45

46
                $this->request          = $request;
8✔
47
                $this->header           = $header;
8✔
48
                $this->httpResponseCode = $httpResponseCode;
8✔
49
        }
50

51
        /**
52
         * @internal
53
         */
54
        public static function incrementRequestCounter( string $tmpPath, ?int $int = null ) : int {
55
                $countFile = $tmpPath . DIRECTORY_SEPARATOR . MockWebServer::REQUEST_COUNT_FILE;
14✔
56

57
                if( $int === null ) {
14✔
58
                        $newInt = file_get_contents($countFile);
9✔
59
                        if( !is_string($newInt) ) {
9✔
60
                                throw new ServerException('failed to fetch request count');
×
61
                        }
62

63
                        $int = (int)$newInt + 1;
9✔
64
                }
65

66
                file_put_contents($countFile, (string)$int);
14✔
67

68
                return (int)$int;
14✔
69
        }
70

71
        private function logRequest( RequestInfo $request, int $count ) : void {
72
                $reqStr = serialize($request);
8✔
73
                file_put_contents($this->tmpPath . DIRECTORY_SEPARATOR . MockWebServer::LAST_REQUEST_FILE, $reqStr);
8✔
74
                file_put_contents($this->tmpPath . DIRECTORY_SEPARATOR . 'request.' . $count, $reqStr);
8✔
75
        }
76

77
        /**
78
         * @internal
79
         */
80
        public static function aliasPath( string $tmpPath, string $path ) : string {
81
                $path = '/' . ltrim($path, '/');
17✔
82

83
                return sprintf('%s%salias.%s',
17✔
84
                        $tmpPath,
17✔
85
                        DIRECTORY_SEPARATOR,
17✔
86
                        md5($path)
17✔
87
                );
17✔
88
        }
89

90
        private function responseForRef( string $ref ) : ?ResponseInterface {
91
                $path = $this->tmpPath . DIRECTORY_SEPARATOR . $ref;
7✔
92
                if( !is_readable($path) ) {
7✔
93
                        return null;
2✔
94
                }
95

96
                $content  = file_get_contents($path);
5✔
97
                if( $content === false ) {
5✔
NEW
98
                        throw new ServerException('failed to read response content');
×
99
                }
100

101
                $response = unserialize($content);
5✔
102
                if( !$response instanceof ResponseInterface ) {
5✔
103
                        throw new ServerException('invalid serialized response');
×
104
                }
105

106
                return $response;
5✔
107
        }
108

109
        public function __invoke() : void {
110
                $ref = $this->getRefForUri($this->request->getParsedUri()['path']);
7✔
111

112
                if( $ref !== null ) {
7✔
113
                        $response = $this->responseForRef($ref);
5✔
114
                        if( $response ) {
5✔
115
                                $this->sendResponse($response);
4✔
116

117
                                return;
4✔
118
                        }
119

120
                        $this->sendResponse(new NotFoundResponse);
1✔
121

122
                        return;
1✔
123
                }
124

125
                $response = $this->responseForRef(self::DEFAULT_REF);
2✔
126
                if( $response ) {
2✔
127
                        $this->sendResponse($response);
1✔
128

129
                        return;
1✔
130
                }
131

132
                $this->sendResponse(new DefaultResponse);
1✔
133
        }
134

135
        protected function sendResponse( ResponseInterface $response ) : void {
136
                if( $response instanceof InitializingResponseInterface ) {
7✔
137
                        $response->initialize($this->request);
1✔
138
                }
139

140
                ($this->httpResponseCode)($response->getStatus($this->request));
7✔
141

142
                foreach( $response->getHeaders($this->request) as $key => $header ) {
7✔
143
                        if( is_int($key) ) {
6✔
144
                                ($this->header)($header);
×
145
                        } else {
146
                                ($this->header)("{$key}: {$header}");
6✔
147
                        }
148
                }
149

150
                echo $response->getBody($this->request);
7✔
151

152
                if( $response instanceof MultiResponseInterface ) {
7✔
153
                        $response->next();
×
154
                        self::storeResponse($this->tmpPath, $response);
×
155
                }
156
        }
157

158
        protected function getRefForUri( string $uriPath ) : ?string {
159
                $aliasPath = self::aliasPath($this->tmpPath, $uriPath);
7✔
160

161
                if( file_exists($aliasPath) ) {
7✔
162
                        if( $path = file_get_contents($aliasPath) ) {
×
163
                                return $path;
×
164
                        }
165
                } elseif( preg_match('%^/' . preg_quote(MockWebServer::VND, '%') . '/([0-9a-fA-F]{32})$%', $uriPath, $matches) ) {
7✔
166
                        return $matches[1];
5✔
167
                }
168

169
                return null;
2✔
170
        }
171

172
        public static function getPathOfRef( string $ref ) : string {
173
                return '/' . MockWebServer::VND . '/' . $ref;
8✔
174
        }
175

176
        /**
177
         * @internal
178
         */
179
        public static function storeResponse( string $tmpPath, ResponseInterface $response ) : string {
180
                $ref = $response->getRef();
16✔
181
                self::storeRef($response, $tmpPath, $ref);
16✔
182

183
                return $ref;
16✔
184
        }
185

186
        /**
187
         * @internal
188
         */
189
        public static function storeDefaultResponse( string $tmpPath, ResponseInterface $response ) : void {
190
                self::storeRef($response, $tmpPath, self::DEFAULT_REF);
2✔
191
        }
192

193
        private static function storeRef( ResponseInterface $response, string $tmpPath, string $ref ) : void {
194
                $content = serialize($response);
17✔
195

196
                if( !file_put_contents($tmpPath . DIRECTORY_SEPARATOR . $ref, $content) ) {
17✔
197
                        throw new Exceptions\RuntimeException('Failed to write temporary content');
×
198
                }
199
        }
200

201
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc