Skip to content

Commit 1b4b1f9

Browse files
committed
Check code for warnings and errors, in both CliRunner and CgiRunner. Ref: php-school#4
1 parent 284372c commit 1b4b1f9

File tree

6 files changed

+141
-16
lines changed

6 files changed

+141
-16
lines changed

src/Exception/CodeExecutionException.php

+37-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,48 @@
1212
*/
1313
class CodeExecutionException extends RuntimeException
1414
{
15+
16+
/**
17+
* @var string
18+
*/
19+
private $actual;
20+
/**
21+
* @var string
22+
*/
23+
private $errors;
24+
25+
/**
26+
* CodeExecutionException constructor.
27+
* @param string $reason
28+
* @param string $actual
29+
* @param string $errors
30+
*/
31+
public function __construct($reason, $actual, $errors) {
32+
$this->message = $reason;
33+
$this->actual = $actual;
34+
$this->errors = $errors;
35+
}
36+
1537
/**
1638
* @param Process $process
1739
* @return static
1840
*/
1941
public static function fromProcess(Process $process)
2042
{
21-
$message = 'PHP Code failed to execute. Error: "%s"';
22-
$processOutput = $process->getErrorOutput() ? $process->getErrorOutput() : $process->getOutput();
23-
return new static(sprintf($message, $processOutput));
43+
$message = "PHP Code failed to execute. Error: \n%s";
44+
$processOutput = $process->getOutput();
45+
$processErrorOutput = $process->getErrorOutput();
46+
return new static(sprintf($message, $processErrorOutput ?: $processOutput), $processOutput, $processErrorOutput);
47+
}
48+
49+
public function getActual()
50+
{
51+
return $this->actual;
2452
}
53+
54+
public function getErrors()
55+
{
56+
return $this->errors;
57+
}
58+
2559
}

src/ExerciseRunner/CgiRunner.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private function checkRequest(RequestInterface $request, $fileName)
9898

9999
try {
100100
$event = $this->eventDispatcher->dispatch(new CgiExecuteEvent('cgi.verify.user-execute.pre', $request));
101-
$userResponse = $this->executePhpFile($fileName, $event->getRequest(), 'user');
101+
list($userResponse, $userWarnings) = $this->executePhpFile($fileName, $event->getRequest(), 'user');
102102
} catch (CodeExecutionException $e) {
103103
$this->eventDispatcher->dispatch(new Event('cgi.verify.user-execute.fail', ['exception' => $e]));
104104
return Failure::fromNameAndCodeExecutionFailure($this->getName(), $e);
@@ -109,8 +109,8 @@ private function checkRequest(RequestInterface $request, $fileName)
109109
$solutionHeaders = $this->getHeaders($solutionResponse);
110110
$userHeaders = $this->getHeaders($userResponse);
111111

112-
if ($solutionBody !== $userBody || $solutionHeaders !== $userHeaders) {
113-
return new CgiOutRequestFailure($request, $solutionBody, $userBody, $solutionHeaders, $userHeaders);
112+
if ($solutionBody !== $userBody || $solutionHeaders !== $userHeaders || $userWarnings) {
113+
return new CgiOutRequestFailure($request, $solutionBody, $userBody, $solutionHeaders, $userHeaders, $userWarnings);
114114
}
115115

116116
return new Success($this->getName());
@@ -153,7 +153,7 @@ private function executePhpFile($fileName, RequestInterface $request, $type)
153153
$output = "HTTP/1.0 200 OK\r\n" . $output;
154154
}
155155

156-
return ResponseSerializer::fromString($output);
156+
return ($type == 'user' ? [ResponseSerializer::fromString($output), $process->getErrorOutput()] : ResponseSerializer::fromString($output));
157157
}
158158

159159
/**

src/ExerciseRunner/CliRunner.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ public function verify($fileName)
110110
list($userOutput, $userWarnings) = $this->executePhpFile($fileName, $event->getArgs(), 'user');
111111
} catch (CodeExecutionException $e) {
112112
$this->eventDispatcher->dispatch(new Event('cli.verify.user-execute.fail', ['exception' => $e]));
113-
return Failure::fromNameAndCodeExecutionFailure($this->getName(), $e);
113+
return Failure::fromNameAndCodeExecutionFailure($this->getName(), $e, $solutionOutput, $e->getActual(), $e->getErrors());
114114
}
115-
if ($solutionOutput === $userOutput) {
115+
if ($solutionOutput === $userOutput || !empty($userWarnings)) {
116116
if (!empty($userWarnings)) {
117117
return StdOutFailure::fromNameAndWarnings($this->getName(), $solutionOutput, $userOutput, $userWarnings);
118118
} else {

src/Result/CgiOutRequestFailure.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,33 @@ class CgiOutRequestFailure implements FailureInterface
3636
*/
3737
private $actualHeaders;
3838

39+
/**
40+
* @var string|null
41+
*/
42+
private $warnings;
43+
3944
/**
4045
* @param RequestInterface $request
4146
* @param string $expectedOutput
4247
* @param string $actualOutput
4348
* @param array $expectedHeaders
4449
* @param array $actualHeaders
50+
* @param string|null $warnings
4551
*/
4652
public function __construct(
4753
RequestInterface $request,
4854
$expectedOutput,
4955
$actualOutput,
5056
array $expectedHeaders,
51-
array $actualHeaders
57+
array $actualHeaders,
58+
$warnings = null
5259
) {
5360
$this->request = $request;
5461
$this->expectedOutput = $expectedOutput;
5562
$this->actualOutput = $actualOutput;
5663
$this->expectedHeaders = $expectedHeaders;
5764
$this->actualHeaders = $actualHeaders;
65+
$this->warnings = $warnings;
5866
}
5967

6068
/**
@@ -128,4 +136,12 @@ public function getCheckName()
128136
{
129137
return 'Request Failure';
130138
}
139+
140+
/**
141+
* @return string|null
142+
*/
143+
public function getWarnings()
144+
{
145+
return $this->warnings;
146+
}
131147
}

src/Result/Failure.php

+51-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ class Failure implements FailureInterface
1818
*/
1919
private $reason;
2020

21+
/**
22+
* @var string|null
23+
*/
24+
private $expectedOutput;
25+
26+
/**
27+
* @var string|null
28+
*/
29+
private $actualOutput;
30+
31+
/**
32+
* @var string|null
33+
*/
34+
private $errors;
35+
2136
/**
2237
* @var string
2338
*/
@@ -26,11 +41,16 @@ class Failure implements FailureInterface
2641
/**
2742
* @param string $name
2843
* @param string|null $reason
44+
* @param string|null $expectedOutput
45+
* @param string|null $actualOutput
2946
*/
30-
public function __construct($name, $reason = null)
47+
public function __construct($name, $reason = null, $expectedOutput = null, $actualOutput = null, $errors = null)
3148
{
32-
$this->name = $name;
33-
$this->reason = $reason;
49+
$this->name = $name;
50+
$this->reason = $reason;
51+
$this->expectedOutput = $expectedOutput;
52+
$this->actualOutput = $actualOutput;
53+
$this->errors = $errors;
3454
}
3555

3656
/**
@@ -56,11 +76,14 @@ public static function fromCheckAndReason(CheckInterface $check, $reason)
5676
/**
5777
* @param string $name
5878
* @param CodeExecutionException $e
79+
* @param string|null $expectedOutput
80+
* @param string|null $actualOutput
81+
* @param string|null $errors
5982
* @return static
6083
*/
61-
public static function fromNameAndCodeExecutionFailure($name, CodeExecutionException $e)
84+
public static function fromNameAndCodeExecutionFailure($name, CodeExecutionException $e, $expectedOutput = null, $actualOutput = null, $errors = null)
6285
{
63-
return new static($name, $e->getMessage());
86+
return new static($name, $e->getMessage(), $expectedOutput, $actualOutput, $errors);
6487
}
6588

6689
/**
@@ -92,4 +115,27 @@ public function getReason()
92115
{
93116
return $this->reason;
94117
}
118+
119+
/**
120+
* @return string|null
121+
*/
122+
public function getExpectedOutput()
123+
{
124+
return $this->expectedOutput;
125+
}
126+
127+
/**
128+
* @return string|null
129+
*/
130+
public function getActualOutput()
131+
{
132+
return $this->actualOutput;
133+
}
134+
135+
/**
136+
* @return string|null
137+
*/
138+
public function getErrors() {
139+
return $this->errors;
140+
}
95141
}

src/ResultRenderer/FailureRenderer.php

+30-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,35 @@ public function __construct(Failure $result)
3030
*/
3131
public function render(ResultsRenderer $renderer)
3232
{
33-
return ' ' . $this->result->getReason() . "\n";
33+
if ($this->result->getExpectedOutput()) {
34+
return sprintf(
35+
" %s\n%s\n\n %s\n%s\n" . ($this->result->getErrors() ? "\n %s\n%s\n" : ""),
36+
$renderer->style("ACTUAL", ['bold', 'underline', 'yellow']),
37+
$this->indent($renderer->style(sprintf('"%s"', $this->result->getActualOutput()), 'red')),
38+
$renderer->style("EXPECTED", ['yellow', 'bold', 'underline']),
39+
$this->indent($renderer->style(sprintf('"%s"', $this->result->getExpectedOutput()), 'red')),
40+
$renderer->style("ERRORS/WARNINGS", ['yellow', 'bold', 'underline']),
41+
$this->indent($renderer->style(sprintf('%s', $this->result->getErrors()), 'red'))
42+
);
43+
} else {
44+
return ' ' . $this->result->getReason() . "\n";
45+
}
46+
}
47+
48+
/**
49+
* @param string $string
50+
* @return string
51+
*/
52+
private function indent($string)
53+
{
54+
return implode(
55+
"\n",
56+
array_map(
57+
function ($line) {
58+
return sprintf(" %s", $line);
59+
},
60+
explode("\n", $string)
61+
)
62+
);
3463
}
3564
}

0 commit comments

Comments
 (0)