<commit_before><?php


namespace PhpSchool\PhpWorkshopTest;

use InvalidArgumentException;
use PhpSchool\PhpWorkshop\CodePatcher;
use PhpSchool\PhpWorkshopTest\Asset\SelfCheckExercise;
use PHPUnit_Framework_TestCase;
use PhpSchool\PhpWorkshop\Check\CheckInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\ExerciseCheck\StdOutExerciseCheck;
use PhpSchool\PhpWorkshop\ExerciseRunner;
use PhpSchool\PhpWorkshop\Result\Failure;
use PhpSchool\PhpWorkshop\Result\Success;
use PhpSchool\PhpWorkshop\ResultAggregator;
use PhpSchool\PhpWorkshopTest\Asset\StdOutExercise;
use stdClass;

/**
 * Class ExerciseRunnerTest
 * @package PhpSchool\PhpWorkshopTest
 * @author <NAME> <<EMAIL>>
 */
class ExerciseRunnerTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var CheckInterface
     */
    private $check;

    /**
     * @var ExerciseRunner
     */
    private $exerciseRunner;

    /**
     * @var CodePatcher
     */
    private $codePatcher;

    /**
     * @var string
     */
    private $file;

    public function setUp()
    {
        $this->check = $this->getMock(CheckInterface::class);
        $this->check
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('Some Check'));
        
        $this->codePatcher = $this->getMockBuilder(CodePatcher::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->exerciseRunner = new ExerciseRunner($this->codePatcher);

        $this->file = sprintf('%s/%s/submission.php', str_replace('\\', '/', sys_get_temp_dir()), $this->getName());
        
        mkdir(dirname($this->file), 0775, true);
        touch($this->file);
    }
    
    public function testRegisterCheckExerciseWithNonStringNonNullThrowsException()
    {
        $this->setExpectedException(
            InvalidArgumentException::class,
            'Expected: "string" Received: "stdClass"'
        );
        $this->exerciseRunner->registerCheck($this->getMock(CheckInterface::class), new stdClass);
    }

    public function testRegisterPreCheckExerciseWithNonStringNonNullThrowsException()
    {
        $this->setExpectedException(
            InvalidArgumentException::class,
            'Expected: "string" Received: "stdClass"'
        );
        $this->exerciseRunner->registerPreCheck($this->getMock(CheckInterface::class), new stdClass);
    }

    public function testRegisterCheck()
    {
        $this->exerciseRunner->registerCheck($this->getMock(CheckInterface::class), 'SomeInterface');
    }

    public function testRegisterPreCheck()
    {
        $this->exerciseRunner->registerPreCheck($this->getMock(CheckInterface::class), 'SomeInterface');
    }

    public function testRunExerciseOnlyRunsRequiredChecksAndPreChecks()
    {
        $doNotRunMe = $this->getMock(CheckInterface::class);

        $doNotRunMe
            ->expects($this->never())
            ->method('check');

        $this->exerciseRunner->registerCheck($doNotRunMe, StdOutExerciseCheck::class);
        $this->exerciseRunner->registerPreCheck($doNotRunMe, StdOutExerciseCheck::class);
        
        $result = $this->exerciseRunner->runExercise($this->getMock(ExerciseInterface::class), $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertTrue($result->isSuccessful());
    }

    public function testRunExerciseWithRequiredChecks()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $this->exerciseRunner->registerCheck($runMe, StdOutExerciseCheck::class);
        
        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Success($this->check)));

        $result = $this->exerciseRunner->runExercise(new StdOutExercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertTrue($result->isSuccessful());
    }

    public function testWhenPreChecksFailTheyReturnImmediatelyEarly()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Failure($this->check, 'nope')));
        

        $doNotRunMe = $this->getMock(CheckInterface::class);
        $doNotRunMe
            ->expects($this->never())
            ->method('check');

        $this->exerciseRunner->registerPreCheck($runMe, StdOutExerciseCheck::class);
        $this->exerciseRunner->registerCheck($doNotRunMe, StdOutExerciseCheck::class);

        $result = $this->exerciseRunner->runExercise(new StdOutExercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertFalse($result->isSuccessful());
    }

    public function testSelfCheck()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $this->exerciseRunner->registerCheck($runMe, ExerciseInterface::class);

        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Success($this->check->getName())));
        
        $result = $this->exerciseRunner->runExercise(new SelfCheckExercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertCount(2, $result);
    }

    public function testCodeWhichRequiresPatchingIsModifiedOnDiskAfterPreChecksAndThenReverted()
    {
        file_put_contents($this->file, 'ORIGINAL CONTENT');

        $exercise = $this->getMock(ExerciseInterface::class);
        $runMe = $this->getMock(CheckInterface::class);
        $runMe
            ->expects($this->once())
            ->method('check')
            ->with($exercise, $this->file)
            ->will($this->returnCallback(function (ExerciseInterface $exercise, $file) {
                $this->assertStringEqualsFile($file, 'MODIFIED CONTENT');
                return new Success('test');
            }));<commit_msg>Fix mocks to return SolutionInterface<commit_after><?php


namespace PhpSchool\PhpWorkshopTest;

use InvalidArgumentException;
use PhpSchool\PhpWorkshop\CodePatcher;
use PhpSchool\PhpWorkshop\Solution\SolutionInterface;
use PhpSchool\PhpWorkshopTest\Asset\SelfCheckExercise;
use PHPUnit_Framework_TestCase;
use PhpSchool\PhpWorkshop\Check\CheckInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\ExerciseCheck\StdOutExerciseCheck;
use PhpSchool\PhpWorkshop\ExerciseRunner;
use PhpSchool\PhpWorkshop\Result\Failure;
use PhpSchool\PhpWorkshop\Result\Success;
use PhpSchool\PhpWorkshop\ResultAggregator;
use PhpSchool\PhpWorkshopTest\Asset\StdOutExercise;
use stdClass;

/**
 * Class ExerciseRunnerTest
 * @package PhpSchool\PhpWorkshopTest
 * @author <NAME> <<EMAIL>>
 */
class ExerciseRunnerTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var CheckInterface
     */
    private $check;

    /**
     * @var ExerciseRunner
     */
    private $exerciseRunner;

    /**
     * @var CodePatcher
     */
    private $codePatcher;

    /**
     * @var string
     */
    private $file;

    public function setUp()
    {
        $this->check = $this->getMock(CheckInterface::class);
        $this->check
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('Some Check'));
        
        $this->codePatcher = $this->getMockBuilder(CodePatcher::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->exerciseRunner = new ExerciseRunner($this->codePatcher);

        $this->file = sprintf('%s/%s/submission.php', str_replace('\\', '/', sys_get_temp_dir()), $this->getName());
        
        mkdir(dirname($this->file), 0775, true);
        touch($this->file);
    }
    
    public function testRegisterCheckExerciseWithNonStringNonNullThrowsException()
    {
        $this->setExpectedException(
            InvalidArgumentException::class,
            'Expected: "string" Received: "stdClass"'
        );
        $this->exerciseRunner->registerCheck($this->getMock(CheckInterface::class), new stdClass);
    }

    public function testRegisterPreCheckExerciseWithNonStringNonNullThrowsException()
    {
        $this->setExpectedException(
            InvalidArgumentException::class,
            'Expected: "string" Received: "stdClass"'
        );
        $this->exerciseRunner->registerPreCheck($this->getMock(CheckInterface::class), new stdClass);
    }

    public function testRegisterCheck()
    {
        $this->exerciseRunner->registerCheck($this->getMock(CheckInterface::class), 'SomeInterface');
    }

    public function testRegisterPreCheck()
    {
        $this->exerciseRunner->registerPreCheck($this->getMock(CheckInterface::class), 'SomeInterface');
    }

    public function testRunExerciseOnlyRunsRequiredChecksAndPreChecks()
    {
        $doNotRunMe = $this->getMock(CheckInterface::class);

        $doNotRunMe
            ->expects($this->never())
            ->method('check');

        $this->exerciseRunner->registerCheck($doNotRunMe, StdOutExerciseCheck::class);
        $this->exerciseRunner->registerPreCheck($doNotRunMe, StdOutExerciseCheck::class);
        
        $solution = $this->getMock(SolutionInterface::class);
        $exercise = $this->getMock(ExerciseInterface::class);
        $exercise->expects($this->any())
            ->method('getSolution')
            ->will($this->returnValue($solution));
        
        $result = $this->exerciseRunner->runExercise($exercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertTrue($result->isSuccessful());
    }

    public function testRunExerciseWithRequiredChecks()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $this->exerciseRunner->registerCheck($runMe, StdOutExerciseCheck::class);
        
        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Success($this->check)));

        $solution = $this->getMock(SolutionInterface::class);
        $exercise = $this->getMock(StdOutExercise::class);
        $exercise->expects($this->any())
            ->method('getSolution')
            ->will($this->returnValue($solution));

        $result = $this->exerciseRunner->runExercise($exercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertTrue($result->isSuccessful());
    }

    public function testWhenPreChecksFailTheyReturnImmediatelyEarly()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Failure($this->check, 'nope')));
        

        $doNotRunMe = $this->getMock(CheckInterface::class);
        $doNotRunMe
            ->expects($this->never())
            ->method('check');

        $solution = $this->getMock(SolutionInterface::class);
        $exercise = $this->getMock(StdOutExercise::class);
        $exercise->expects($this->any())
            ->method('getSolution')
            ->will($this->returnValue($solution));

        $this->exerciseRunner->registerPreCheck($runMe, StdOutExerciseCheck::class);
        $this->exerciseRunner->registerCheck($doNotRunMe, StdOutExerciseCheck::class);

        $result = $this->exerciseRunner->runExercise($exercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertFalse($result->isSuccessful());
    }

    public function testSelfCheck()
    {
        $runMe = $this->getMock(CheckInterface::class);
        $this->exerciseRunner->registerCheck($runMe, ExerciseInterface::class);

        $runMe
            ->expects($this->once())
            ->method('check')
            ->will($this->returnValue(new Success($this->check->getName())));

        $solution = $this->getMock(SolutionInterface::class);
        $exercise = $this->getMock(SelfCheckExercise::class, ['getSolution']);
        $exercise->expects($this->any())
            ->method('getSolution')
            ->will($this->returnValue($solution));
        
        $result = $this->exerciseRunner->runExercise($exercise, $this->file);
        $this->assertInstanceOf(ResultAggregator::class, $result);
        $this->assertCount(2, $result);
    }

    public function testCodeWhichRequiresPatchingIsModifiedOnDiskAfterPreChecksAndThenReverted()
    {
        file_put_contents($this->file, 'ORIGINAL CONTENT');

        $solution = $this->getMock(SolutionInterface::class);
        $exercise = $this->getMock(ExerciseInterface::class);
        $exercise->expects($this->any())
            ->method('getSolution')
            ->will($this->returnValue($solution));
        
        $runMe = $this->getMock(CheckInterface::class);
        $runMe
            ->expects($this->once())
            ->method('check')
            ->with($exercise, $this->file)
            ->will($this->returnCallback(function (ExerciseInterface $exercise, $file) {
                $this->assertStringEqualsFile($file, 'MODIFIED CONTENT');
                return new Success('test');
            }));
{'fraction_non_alphanumeric': 0.14634331186055324, 'fraction_numerical': 0.0007578628268283441, 'mean_word_length': 3.095592799503414, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 260, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3488016', 'n_tokens_mistral': 3845, 'n_tokens_neox': 3680, 'n_words': 487}