Skip to content

Commit dd9cee5

Browse files
authored
Merge pull request #141 from php-school/custom-runner
Custom runner
2 parents 8a0a1ee + f8b96bf commit dd9cee5

File tree

9 files changed

+321
-6
lines changed

9 files changed

+321
-6
lines changed

app/config.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
2323
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CgiRunnerFactory;
2424
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory;
25+
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CustomVerifyingRunnerFactory;
2526
use PhpSchool\PhpWorkshop\ExerciseRunner\RunnerManager;
2627
use PhpSchool\PhpWorkshop\Factory\EventDispatcherFactory;
2728
use PhpSchool\PhpWorkshop\Factory\MenuFactory;
@@ -125,6 +126,7 @@
125126
$manager = new RunnerManager;
126127
$manager->addFactory(new CliRunnerFactory($c->get(EventDispatcher::class)));
127128
$manager->addFactory(new CgiRunnerFactory($c->get(EventDispatcher::class)));
129+
$manager->addFactory(new CustomVerifyingRunnerFactory);
128130
return $manager;
129131
},
130132

@@ -326,25 +328,25 @@
326328
containerListener(CodePatchListener::class, 'patch'),
327329
],
328330
'cli.verify.finish' => [
329-
containerListener(CodePatchListener::class, 'patch'),
331+
containerListener(CodePatchListener::class, 'revert'),
330332
],
331333
'cli.run.start' => [
332334
containerListener(CodePatchListener::class, 'patch'),
333335
],
334336
'cli.run.finish' => [
335-
containerListener(CodePatchListener::class, 'patch'),
337+
containerListener(CodePatchListener::class, 'revert'),
336338
],
337339
'cgi.verify.start' => [
338340
containerListener(CodePatchListener::class, 'patch'),
339341
],
340342
'cgi.verify.finish' => [
341-
containerListener(CodePatchListener::class, 'patch'),
343+
containerListener(CodePatchListener::class, 'revert'),
342344
],
343345
'cgi.run.start' => [
344346
containerListener(CodePatchListener::class, 'patch'),
345347
],
346348
'cgi.run.finish' => [
347-
containerListener(CodePatchListener::class, 'patch'),
349+
containerListener(CodePatchListener::class, 'revert'),
348350
],
349351
],
350352
'self-check' => [
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\Exercise;
4+
5+
use PhpSchool\PhpWorkshop\Result\ResultInterface;
6+
7+
/**
8+
* @author Aydin Hassan <[email protected]>
9+
*/
10+
interface CustomVerifyingExercise
11+
{
12+
/**
13+
* @return ResultInterface
14+
*/
15+
public function verify();
16+
}

src/Exercise/ExerciseType.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class ExerciseType extends Enum
2020
{
2121
const CLI = 'CLI';
2222
const CGI = 'CGI';
23+
const CUSTOM = 'CUSTOM';
24+
2325

2426
/**
2527
* Map of exercise types to the required interfaces exercises of that particular
@@ -30,6 +32,7 @@ class ExerciseType extends Enum
3032
private static $exerciseTypeToExerciseInterfaceMap = [
3133
self::CLI => CliExercise::class,
3234
self::CGI => CgiExercise::class,
35+
self::CUSTOM => CustomVerifyingExercise::class,
3336
];
3437

3538
/**
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\CustomVerifyingExercise;
6+
use PhpSchool\PhpWorkshop\Input\Input;
7+
use PhpSchool\PhpWorkshop\Output\OutputInterface;
8+
use PhpSchool\PhpWorkshop\Result\ResultInterface;
9+
10+
/**
11+
* @author Aydin Hassan <[email protected]>
12+
*/
13+
class CustomVerifyingRunner implements ExerciseRunnerInterface
14+
{
15+
/**
16+
* @var CustomVerifyingExercise
17+
*/
18+
private $exercise;
19+
20+
/**
21+
* @param CustomVerifyingExercise $exercise
22+
*/
23+
public function __construct(CustomVerifyingExercise $exercise)
24+
{
25+
$this->exercise = $exercise;
26+
}
27+
28+
/**
29+
* Get the name of the exercise runner.
30+
*
31+
* @return string
32+
*/
33+
public function getName()
34+
{
35+
return 'Custom Verifying Runner';
36+
}
37+
38+
/**
39+
* Get an array of the class names of the required checks this runner needs.
40+
*
41+
* @return array
42+
*/
43+
public function getRequiredChecks()
44+
{
45+
return [];
46+
}
47+
48+
/**
49+
* Delegate to the exercise for verifying. Verifying could mean checking that a program was installed or that some
50+
* other arbitrary task was performed.
51+
*
52+
* @param Input $input The command line arguments passed to the command.
53+
* @return ResultInterface The result of the check.
54+
*/
55+
public function verify(Input $input)
56+
{
57+
return $this->exercise->verify();
58+
}
59+
60+
/**
61+
* Running a custom verifying exercise does nothing. There is no program required, therefore there is nothing
62+
* to run.
63+
*
64+
* @param Input $input The command line arguments passed to the command.
65+
* @param OutputInterface $output A wrapper around STDOUT.
66+
* @return bool If the solution was successfully executed, eg. exit code was 0.
67+
*/
68+
public function run(Input $input, OutputInterface $output)
69+
{
70+
$message = 'Nothing to run here. This exercise does not require a code solution, ';
71+
$message .= 'so there is nothing to execute.';
72+
$output->writeLine($message);
73+
return true;
74+
}
75+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner\Factory;
4+
5+
use PhpSchool\PhpWorkshop\CommandDefinition;
6+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
7+
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
8+
use PhpSchool\PhpWorkshop\ExerciseRunner\CustomVerifyingRunner;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\ExerciseRunnerInterface;
10+
11+
/**
12+
* @author Aydin Hassan <[email protected]>
13+
*/
14+
class CustomVerifyingRunnerFactory implements ExerciseRunnerFactoryInterface
15+
{
16+
/**
17+
* @var string
18+
*/
19+
private static $type = ExerciseType::CUSTOM;
20+
21+
/**
22+
* Whether the factory supports this exercise type.
23+
*
24+
* @param ExerciseInterface $exercise
25+
* @return bool
26+
*/
27+
public function supports(ExerciseInterface $exercise)
28+
{
29+
return $exercise->getType()->getValue() === self::$type;
30+
}
31+
32+
/**
33+
* Add any extra required arguments to the command.
34+
*
35+
* @param CommandDefinition $commandDefinition
36+
*/
37+
public function configureInput(CommandDefinition $commandDefinition)
38+
{
39+
}
40+
41+
/**
42+
* Create and return an instance of the runner.
43+
*
44+
* @param ExerciseInterface $exercise
45+
* @return ExerciseRunnerInterface
46+
*/
47+
public function create(ExerciseInterface $exercise)
48+
{
49+
return new CustomVerifyingRunner($exercise);
50+
}
51+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest\Asset;
4+
5+
use PhpSchool\PhpWorkshop\Exercise\AbstractExercise;
6+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
7+
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
8+
use PhpSchool\PhpWorkshop\Exercise\CustomVerifyingExercise;
9+
use PhpSchool\PhpWorkshop\Result\ResultInterface;
10+
use PhpSchool\PhpWorkshop\Result\Success;
11+
12+
/**
13+
* @author Aydin Hassan <[email protected]>
14+
*/
15+
class CustomVerifyingExerciseImpl extends AbstractExercise implements ExerciseInterface, CustomVerifyingExercise
16+
{
17+
18+
/**
19+
* Get the name of the exercise, like `Hello World!`.
20+
*
21+
* @return string
22+
*/
23+
public function getName()
24+
{
25+
return 'Custom Verifying exercise';
26+
}
27+
28+
/**
29+
* A short description of the exercise.
30+
*
31+
* @return string
32+
*/
33+
public function getDescription()
34+
{
35+
return 'Custom Verifying exercise';
36+
}
37+
38+
/**
39+
* Return the type of exercise. This is an ENUM. See `PhpSchool\PhpWorkshop\Exercise\ExerciseType`.
40+
*
41+
* @return ExerciseType
42+
*/
43+
public function getType()
44+
{
45+
return ExerciseType::CUSTOM();
46+
}
47+
48+
/**
49+
* @return ResultInterface
50+
*/
51+
public function verify()
52+
{
53+
return new Success('success');
54+
}
55+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshop\ExerciseRunner;
4+
5+
use Colors\Color;
6+
use PhpSchool\CliMenu\Terminal\TerminalInterface;
7+
use PhpSchool\PhpWorkshop\Input\Input;
8+
use PhpSchool\PhpWorkshop\Output\StdOutput;
9+
use PhpSchool\PhpWorkshopTest\Asset\CustomVerifyingExerciseImpl;
10+
use PHPUnit_Framework_TestCase;
11+
12+
/**
13+
* @author Aydin Hassan <[email protected]>
14+
*/
15+
class ExtRunnerTest extends PHPUnit_Framework_TestCase
16+
{
17+
/**
18+
* @var CustomVerifyingRunner
19+
*/
20+
private $runner;
21+
22+
/**
23+
* @var CustomVerifyingExerciseImpl
24+
*/
25+
private $exercise;
26+
27+
public function setUp()
28+
{
29+
$this->exercise = new CustomVerifyingExerciseImpl;
30+
$this->runner = new CustomVerifyingRunner($this->exercise);
31+
32+
$this->assertEquals('Custom Verifying Runner', $this->runner->getName());
33+
}
34+
35+
public function testRequiredChecks()
36+
{
37+
$this->assertEquals([], $this->runner->getRequiredChecks());
38+
}
39+
40+
public function testRunOutputsErrorMessage()
41+
{
42+
$color = new Color;
43+
$color->setForceStyle(true);
44+
$output = new StdOutput($color, $this->createMock(TerminalInterface::class));
45+
46+
$exp = 'Nothing to run here. This exercise does not require a code solution, ';
47+
$exp .= "so there is nothing to execute.\n";
48+
49+
$this->expectOutputString($exp);
50+
51+
$this->runner->run(new Input('app'), $output);
52+
}
53+
54+
public function testVerifyProxiesToExercise()
55+
{
56+
self::assertEquals($this->exercise->verify(), $this->runner->verify(new Input('app')));
57+
}
58+
}

test/ExerciseRunner/Factory/CliRunnerFactoryTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44

55
use PhpSchool\PhpWorkshop\CommandDefinition;
66
use PhpSchool\PhpWorkshop\Event\EventDispatcher;
7-
use PhpSchool\PhpWorkshop\Exercise\CliExercise;
87
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
98
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
109
use PhpSchool\PhpWorkshop\ExerciseRunner\CliRunner;
1110
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CliRunnerFactory;
1211
use PhpSchool\PhpWorkshopTest\Asset\CliExerciseImpl;
13-
use PhpSchool\PhpWorkshopTest\Asset\CliExerciseInterface;
1412
use PHPUnit_Framework_TestCase;
1513

1614
/**
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace PhpSchool\PhpWorkshopTest\ExerciseRunner\Factory;
4+
5+
use PhpSchool\PhpWorkshop\CommandDefinition;
6+
use PhpSchool\PhpWorkshop\Exercise\CustomVerifyingExercise;
7+
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
8+
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
9+
use PhpSchool\PhpWorkshop\ExerciseRunner\CustomVerifyingRunner;
10+
use PhpSchool\PhpWorkshop\ExerciseRunner\Factory\CustomVerifyingRunnerFactory;
11+
use PhpSchool\PhpWorkshopTest\Asset\CustomVerifyingExerciseImpl;
12+
use PHPUnit_Framework_TestCase;
13+
14+
/**
15+
* @author Aydin Hassan <[email protected]>
16+
*/
17+
class CustomRunnerFactoryTest extends PHPUnit_Framework_TestCase
18+
{
19+
/**
20+
* @var CustomVerifyingRunnerFactory
21+
*/
22+
private $factory;
23+
24+
public function setUp()
25+
{
26+
$this->factory = new CustomVerifyingRunnerFactory;
27+
}
28+
29+
public function testSupports()
30+
{
31+
$exercise1 = $this->prophesize(ExerciseInterface::class);
32+
$exercise2 = $this->prophesize(ExerciseInterface::class);
33+
$exercise3 = $this->prophesize(ExerciseInterface::class);
34+
35+
$exercise1->getType()->willReturn(ExerciseType::CLI());
36+
$exercise2->getType()->willReturn(ExerciseType::CGI());
37+
$exercise3->getType()->willReturn(ExerciseType::CUSTOM());
38+
39+
$this->assertFalse($this->factory->supports($exercise1->reveal()));
40+
$this->assertFalse($this->factory->supports($exercise2->reveal()));
41+
$this->assertTrue($this->factory->supports($exercise3->reveal()));
42+
}
43+
44+
public function testConfigureInputAddsNoArgument()
45+
{
46+
$command = new CommandDefinition('my-command', [], 'var_dump');
47+
48+
$this->factory->configureInput($command);
49+
$this->assertCount(0, $command->getRequiredArgs());
50+
}
51+
52+
public function testCreateReturnsRunner()
53+
{
54+
$exercise = new CustomVerifyingExerciseImpl;
55+
$this->assertInstanceOf(CustomVerifyingRunner::class, $this->factory->create($exercise));
56+
}
57+
}

0 commit comments

Comments
 (0)