Skip to content

Commit 0ea1c7d

Browse files
committed
Use scenarios in exercises
1 parent b9c0f31 commit 0ea1c7d

11 files changed

+277
-335
lines changed

Diff for: phpstan.neon

-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
parameters:
22
treatPhpDocTypesAsCertain: false
33
ignoreErrors:
4-
-
5-
message: '#PhpSchool\\PhpWorkshop\\ExerciseRunner\\CliRunner\:\:preserveOldArgFormat\(\) should return#'
6-
path: src/ExerciseRunner/CliRunner.php
74
-
85
message: '#Call to an undefined method PhpParser\\Node\\Expr\|PhpParser\\Node\\Name\:\:__toString\(\)#'
96
path: src/Check/FunctionRequirementsCheck.php

Diff for: src/Exercise/CgiExercise.php

+10-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpSchool\PhpWorkshop\Exercise;
66

7+
use PhpSchool\PhpWorkshop\Exercise\Scenario\CgiScenario;
78
use Psr\Http\Message\RequestInterface;
89

910
/**
@@ -12,10 +13,15 @@
1213
interface CgiExercise extends ProvidesSolution
1314
{
1415
/**
15-
* This method should return an array of PSR-7 requests, which will be forwarded to the student's
16-
* solution.
16+
* This method should return an instance of CgiScenario which contains PSR-7 requests,
17+
* which will be forwarded to the student's solution.
1718
*
18-
* @return array<RequestInterface> An array of PSR-7 requests.
19+
* Use like so:
20+
*
21+
* ```
22+
* return (new CgiScenario())
23+
* ->withExecution($request1)
24+
* ```
1925
*/
20-
public function getRequests(): array;
26+
public function defineTestScenario(): CgiScenario;
2127
}

Diff for: src/Exercise/CliExercise.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@
44

55
namespace PhpSchool\PhpWorkshop\Exercise;
66

7+
use PhpSchool\PhpWorkshop\Exercise\Scenario\CliScenario;
8+
79
/**
810
* This interface describes the additional methods a CLI type exercise should implement.
911
*/
1012
interface CliExercise extends ProvidesSolution
1113
{
1214
/**
13-
* This method should return an array of an array of strings.
14-
* Each set of arguments will be passed to the students solution as command line arguments.
15+
* This method should return an instance of CliScenario which contains sets of arguments,
16+
* which will be passed to the students solution as command line arguments.
17+
*
18+
* Use like so:
1519
*
16-
* @return array<array<string>> An array of string arguments.
20+
* ```
21+
* return (new CliScenario())
22+
* ->withExecution(['arg1', 'arg2'])
23+
* ->withExecution(['round2-arg1', 'round2-arg2'])
24+
* ```
1725
*/
18-
public function getArgs(): array;
26+
public function defineTestScenario(): CliScenario;
1927
}

Diff for: src/ExerciseRunner/CgiRunner.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,16 @@ public function getRequiredChecks(): array
104104
*/
105105
public function verify(Input $input): ResultInterface
106106
{
107+
$scenario = $this->exercise->defineTestScenario();
108+
107109
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.start', $this->exercise, $input));
110+
108111
$result = new CgiResult(
109112
array_map(
110113
function (RequestInterface $request) use ($input) {
111114
return $this->doVerify($request, $input);
112115
},
113-
$this->exercise->getRequests()
116+
$scenario->getExecutions()
114117
)
115118
);
116119
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.verify.finish', $this->exercise, $input));
@@ -283,9 +286,12 @@ private function getPhpProcess(string $workingDirectory, string $fileName, Reque
283286
*/
284287
public function run(Input $input, OutputInterface $output): bool
285288
{
289+
$scenario = $this->exercise->defineTestScenario();
290+
286291
$this->eventDispatcher->dispatch(new CgiExerciseRunnerEvent('cgi.run.start', $this->exercise, $input));
292+
287293
$success = true;
288-
foreach ($this->exercise->getRequests() as $i => $request) {
294+
foreach ($scenario->getExecutions() as $i => $request) {
289295
/** @var CgiExecuteEvent $event */
290296
$event = $this->eventDispatcher->dispatch(
291297
new CgiExecuteEvent('cgi.run.student-execute.pre', $this->exercise, $input, $request)

Diff for: src/ExerciseRunner/CliRunner.php

+12-27
Original file line numberDiff line numberDiff line change
@@ -101,46 +101,28 @@ public function getRequiredChecks(): array
101101
*/
102102
public function verify(Input $input): ResultInterface
103103
{
104+
$scenario = $this->exercise->defineTestScenario();
105+
104106
$this->eventDispatcher->dispatch(new CliExerciseRunnerEvent('cli.verify.start', $this->exercise, $input));
105107
$result = new CliResult(
106108
array_map(
107-
function (array $args) use ($input) {
108-
return $this->doVerify($args, $input);
109+
function (Collection $args) use ($input) {
110+
return $this->doVerify($input, $args);
109111
},
110-
$this->preserveOldArgFormat($this->exercise->getArgs())
112+
$scenario->getExecutions()
111113
)
112114
);
113115
$this->eventDispatcher->dispatch(new CliExerciseRunnerEvent('cli.verify.finish', $this->exercise, $input));
114116
return $result;
115117
}
116118

117119
/**
118-
* BC - getArgs only returned 1 set of args in v1 instead of multiple sets of args in v2
119-
*
120-
* @param array<int, array<string>>|array<int, string> $args
121-
* @return array<int, array<string>>
122-
*/
123-
private function preserveOldArgFormat(array $args): array
124-
{
125-
if (isset($args[0]) && !is_array($args[0])) {
126-
$args = [$args];
127-
} elseif (count($args) === 0) {
128-
$args = [[]];
129-
}
130-
131-
return $args;
132-
}
133-
134-
/**
135-
* @param array<string> $args
136120
* @param Input $input
121+
* @param Collection<int, string> $args
137122
* @return CliResultInterface
138123
*/
139-
private function doVerify(array $args, Input $input): CliResultInterface
124+
private function doVerify(Input $input, Collection $args): CliResultInterface
140125
{
141-
//arrays are not pass-by-ref
142-
$args = new ArrayObject($args);
143-
144126
try {
145127
/** @var CliExecuteEvent $event */
146128
$event = $this->eventDispatcher->dispatch(
@@ -213,12 +195,15 @@ private function doVerify(array $args, Input $input): CliResultInterface
213195
*/
214196
public function run(Input $input, OutputInterface $output): bool
215197
{
198+
$scenario = $this->exercise->defineTestScenario();
199+
216200
$this->eventDispatcher->dispatch(new CliExerciseRunnerEvent('cli.run.start', $this->exercise, $input));
201+
217202
$success = true;
218-
foreach ($this->preserveOldArgFormat($this->exercise->getArgs()) as $i => $args) {
203+
foreach ($scenario->getExecutions() as $i => $args) {
219204
/** @var CliExecuteEvent $event */
220205
$event = $this->eventDispatcher->dispatch(
221-
new CliExecuteEvent('cli.run.student-execute.pre', $this->exercise, $input, new ArrayObject($args))
206+
new CliExecuteEvent('cli.run.student-execute.pre', $this->exercise, $input, $args)
222207
);
223208

224209
$args = $event->getArgs();

Diff for: test/Asset/CgiExerciseImpl.php

+21-17
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22

33
namespace PhpSchool\PhpWorkshopTest\Asset;
44

5-
use PhpSchool\PhpWorkshop\Check\FileComparisonCheck;
65
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
76
use PhpSchool\PhpWorkshop\Exercise\CgiExercise;
87
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
98
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\Exercise\Scenario\CgiScenario;
1010
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
1111
use PhpSchool\PhpWorkshop\Solution\SolutionInterface;
1212
use Psr\Http\Message\RequestInterface;
1313

1414
class CgiExerciseImpl implements ExerciseInterface, CgiExercise
1515
{
16-
/**
17-
* @var string
18-
*/
19-
private $name;
16+
private string $name;
17+
private SolutionInterface $solution;
18+
private CgiScenario $scenario;
2019

2120
public function __construct(string $name = 'my-exercise')
2221
{
2322
$this->name = $name;
23+
$this->scenario = new CgiScenario();
2424
}
2525

2626
public function getName(): string
@@ -33,9 +33,14 @@ public function getDescription(): string
3333
return $this->name;
3434
}
3535

36+
public function setSolution(SolutionInterface $solution): void
37+
{
38+
$this->solution = $solution;
39+
}
40+
3641
public function getSolution(): SolutionInterface
3742
{
38-
// TODO: Implement getSolution() method.
43+
return $this->solution;
3944
}
4045

4146
public function getProblem(): string
@@ -48,17 +53,6 @@ public function tearDown(): void
4853
// TODO: Implement tearDown() method.
4954
}
5055

51-
/**
52-
* This method should return an array of PSR-7 requests, which will be forwarded to the student's
53-
* solution.
54-
*
55-
* @return RequestInterface[] An array of PSR-7 requests.
56-
*/
57-
public function getRequests(): array
58-
{
59-
return []; // TODO: Implement getRequests() method.
60-
}
61-
6256
public function getType(): ExerciseType
6357
{
6458
return ExerciseType::CGI();
@@ -72,4 +66,14 @@ public function getRequiredChecks(): array
7266
public function defineListeners(EventDispatcher $dispatcher): void
7367
{
7468
}
69+
70+
public function setScenario(CgiScenario $scenario): void
71+
{
72+
$this->scenario = $scenario;
73+
}
74+
75+
public function defineTestScenario(): CgiScenario
76+
{
77+
return $this->scenario;
78+
}
7579
}

Diff for: test/Asset/CliExerciseImpl.php

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,25 @@
22

33
namespace PhpSchool\PhpWorkshopTest\Asset;
44

5-
use PhpSchool\PhpWorkshop\Check\FileComparisonCheck;
65
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
76
use PhpSchool\PhpWorkshop\Exercise\CliExercise;
87
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
98
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
109
use PhpSchool\PhpWorkshop\Exercise\ProvidesSolution;
10+
use PhpSchool\PhpWorkshop\Exercise\Scenario\CliScenario;
1111
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
1212
use PhpSchool\PhpWorkshop\Solution\SolutionInterface;
1313

1414
class CliExerciseImpl implements ExerciseInterface, CliExercise
1515
{
16-
/**
17-
* @var string
18-
*/
19-
private $name;
20-
21-
/**
22-
* @var SolutionInterface
23-
*/
24-
private $solution;
16+
private string $name;
17+
private SolutionInterface $solution;
18+
private CliScenario $scenario;
2519

2620
public function __construct(string $name = 'my-exercise')
2721
{
2822
$this->name = $name;
23+
$this->scenario = new CliScenario();
2924
}
3025

3126
public function getName(): string
@@ -58,9 +53,14 @@ public function tearDown(): void
5853
// TODO: Implement tearDown() method.
5954
}
6055

61-
public function getArgs(): array
56+
public function setScenario(CliScenario $scenario): void
57+
{
58+
$this->scenario = $scenario;
59+
}
60+
61+
public function defineTestScenario(): CliScenario
6262
{
63-
return []; // TODO: Implement getArgs() method.
63+
return $this->scenario;
6464
}
6565

6666
public function getType(): ExerciseType

0 commit comments

Comments
 (0)