From 212ea6328a0d27bd4ce65a0e149dfeee102c72bc Mon Sep 17 00:00:00 2001 From: pfwd Date: Sun, 20 Nov 2022 17:07:40 +0000 Subject: [PATCH] #157 WIP --- api/src/Markdown/Extractor/DOMExtractor.php | 28 +++++++++-------- api/src/Markdown/Parser/MarkdownParser.php | 30 +++++++++++++++++++ api/src/Markdown/QuestionGenerator.php | 4 ++- .../Extractor/CorrectAnswerExtractorTest.php | 8 ++--- .../Extractor/PossibleAnswerExtractorTest.php | 24 +++++++-------- .../Extractor/QuestionExtractorTest.php | 16 +++++----- .../src/Markdown/QuestionGeneratorTest.php | 27 ++++++++++++++--- .../src/Markdown/QuestionIDGeneratorTest.php | 14 ++++++--- .../Markdown/QuestionQuizIDGeneratorTest.php | 13 +++++--- .../Markdown/QuestionTitleGeneratorTest.php | 7 +++-- 10 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 api/src/Markdown/Parser/MarkdownParser.php diff --git a/api/src/Markdown/Extractor/DOMExtractor.php b/api/src/Markdown/Extractor/DOMExtractor.php index ef7a7a5..ff857af 100644 --- a/api/src/Markdown/Extractor/DOMExtractor.php +++ b/api/src/Markdown/Extractor/DOMExtractor.php @@ -7,30 +7,32 @@ class DOMExtractor { - /** @var DOMNode[] **/ + /** @var DOMNode[] * */ private array $question = []; - /** @var DOMNode[] **/ + /** @var DOMNode[] * */ private array $possibleAnswers = []; - /** @var DOMNode[] **/ + /** @var DOMNode[] * */ private array $correctAnswer = []; private bool $foundPossibleAnswers = false; private bool $foundCorrectAnswer = false; - public function __construct(private readonly string $document) - { - } - /** - * @return void + * @return array{question: DOMNode[], possible_answers: DOMNode[], correct_answer:DOMNode[] } */ - public function extract(): void + public function extract(string $document): array { $domDocument = new DOMDocument(); libxml_use_internal_errors(true); - $domDocument->loadHTML($this->document); + $domDocument->loadHTML($document); $this->process($domDocument); + + return [ + 'question' => $this->question, + 'possible_answers' => $this->possibleAnswers, + 'correct_answer' => $this->correctAnswer + ]; } public function process(DOMNode $domNode): void @@ -72,19 +74,19 @@ public function process(DOMNode $domNode): void } } - /** @return DOMNode[] **/ + /** @return DOMNode[] * */ public function getQuestionNodes(): array { return $this->question; } - /** @return DOMNode[] **/ + /** @return DOMNode[] * */ public function getPossibleAnswerNodes(): array { return $this->possibleAnswers; } - /** @return DOMNode[] **/ + /** @return DOMNode[] * */ public function getCorrectAnswerNodes(): array { return $this->correctAnswer; diff --git a/api/src/Markdown/Parser/MarkdownParser.php b/api/src/Markdown/Parser/MarkdownParser.php new file mode 100644 index 0000000..9035369 --- /dev/null +++ b/api/src/Markdown/Parser/MarkdownParser.php @@ -0,0 +1,30 @@ +getFilePath(); + $markdown = file_get_contents($filePath); + + $html = $this->parsedown->parse($markdown); + + $parts = $this->DOMExtractor->extract($html); + + $question->setContent($parts['question']) + ->setCorrectAnswer($parts['correct_answer']) + ->setPossibleAnswers($parts['possible_answers']); + return $question; + } +} diff --git a/api/src/Markdown/QuestionGenerator.php b/api/src/Markdown/QuestionGenerator.php index cd114aa..4e5094c 100644 --- a/api/src/Markdown/QuestionGenerator.php +++ b/api/src/Markdown/QuestionGenerator.php @@ -3,10 +3,11 @@ namespace App\Markdown; use App\Markdown\Model\Question; +use App\Markdown\Parser\MarkdownParser; class QuestionGenerator implements GeneratorInterface { - public function __construct(private readonly FetcherInterface $fetcher) + public function __construct(private readonly FetcherInterface $fetcher, private readonly MarkdownParser $markdownParser) { } @@ -74,6 +75,7 @@ public function process(array $filePaths): array } $question = new Question($questionID, $quizID, $filePath, $title); + $question = $this->markdownParser->parser($question); $dataSets[] = $question; } diff --git a/api/tests/unit/src/Markdown/Extractor/CorrectAnswerExtractorTest.php b/api/tests/unit/src/Markdown/Extractor/CorrectAnswerExtractorTest.php index 683a82e..f1b7403 100644 --- a/api/tests/unit/src/Markdown/Extractor/CorrectAnswerExtractorTest.php +++ b/api/tests/unit/src/Markdown/Extractor/CorrectAnswerExtractorTest.php @@ -18,8 +18,8 @@ public function setUp(): void public function testAnswerElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getCorrectAnswerNodes(); self::assertSame('p', $questionNodes[4]->nodeName); @@ -27,8 +27,8 @@ public function testAnswerElement() public function testAnswerValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getCorrectAnswerNodes(); self::assertSame('Answer: 5', trim($questionNodes[4]->nodeValue)); diff --git a/api/tests/unit/src/Markdown/Extractor/PossibleAnswerExtractorTest.php b/api/tests/unit/src/Markdown/Extractor/PossibleAnswerExtractorTest.php index e9597ee..6cff6c6 100644 --- a/api/tests/unit/src/Markdown/Extractor/PossibleAnswerExtractorTest.php +++ b/api/tests/unit/src/Markdown/Extractor/PossibleAnswerExtractorTest.php @@ -18,8 +18,8 @@ public function setUp(): void public function testHeadingValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); self::assertSame('Possible answers', $nodes[0]->nodeValue); @@ -27,8 +27,8 @@ public function testHeadingValue() public function testHeadingElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); self::assertSame('h2', $nodes[0]->nodeName); @@ -36,8 +36,8 @@ public function testHeadingElement() public function testFirstPossibleAnswerValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); self::assertSame('[ ] 3', $nodes[2]->nodeValue); @@ -45,8 +45,8 @@ public function testFirstPossibleAnswerValue() public function testFirstPossibleAnswerElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); self::assertSame('li', $nodes[2]->nodeName); @@ -55,8 +55,8 @@ public function testFirstPossibleAnswerElement() public function testLastPossibleAnswerValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); $lastIndex = count($nodes) - 1; @@ -65,8 +65,8 @@ public function testLastPossibleAnswerValue() public function testLastPossibleAnswerElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $nodes = $parser->getPossibleAnswerNodes(); $lastIndex = count($nodes) - 1; diff --git a/api/tests/unit/src/Markdown/Extractor/QuestionExtractorTest.php b/api/tests/unit/src/Markdown/Extractor/QuestionExtractorTest.php index e357666..eaa221e 100644 --- a/api/tests/unit/src/Markdown/Extractor/QuestionExtractorTest.php +++ b/api/tests/unit/src/Markdown/Extractor/QuestionExtractorTest.php @@ -19,8 +19,8 @@ public function setUp(): void public function testQuestionHeadingValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getQuestionNodes(); self::assertSame('This is the question', $questionNodes[0]->nodeValue); @@ -28,8 +28,8 @@ public function testQuestionHeadingValue() public function testQuestionHeadingElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getQuestionNodes(); self::assertSame('h1', $questionNodes[0]->nodeName); @@ -37,8 +37,8 @@ public function testQuestionHeadingElement() public function testLastQuestionElement() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getQuestionNodes(); $count = count($questionNodes) - 1; @@ -47,8 +47,8 @@ public function testLastQuestionElement() public function testLastQuestionValue() { - $parser = new DOMExtractor($this->document); - $parser->extract(); + $parser = new DOMExtractor(); + $parser->extract($this->document); $questionNodes = $parser->getQuestionNodes(); $count = count($questionNodes) - 1; diff --git a/api/tests/unit/src/Markdown/QuestionGeneratorTest.php b/api/tests/unit/src/Markdown/QuestionGeneratorTest.php index 3505afa..5328221 100644 --- a/api/tests/unit/src/Markdown/QuestionGeneratorTest.php +++ b/api/tests/unit/src/Markdown/QuestionGeneratorTest.php @@ -3,6 +3,8 @@ namespace App\Tests\unit\src\Markdown; use App\Markdown\FetcherInterface; +use App\Markdown\Model\Question; +use App\Markdown\Parser\MarkdownParser; use App\Markdown\QuestionFetcher; use App\Markdown\QuizFetcher; use App\Markdown\QuestionGenerator; @@ -31,7 +33,13 @@ public function setUp(): void public function testGeneratedQuestionID() { - $quizGenerator = new QuestionGenerator($this->fetcherMock); + $question = $this->createMock(Question::class); + $question->expects(self::once())->method('getId')->willReturn(2); + + $parserMock = $this->createMock(MarkdownParser::class); + $parserMock->expects(self::any())->method('parser')->willReturn($question); + + $quizGenerator = new QuestionGenerator($this->fetcherMock, $parserMock); $dataSets = $quizGenerator->generate(self::SOURCE); $question2 = $dataSets[1]; @@ -41,19 +49,30 @@ public function testGeneratedQuestionID() public function testGeneratedQuizID() { - $quizGenerator = new QuestionGenerator($this->fetcherMock); + $question = $this->createMock(Question::class); + $question->expects(self::once())->method('getQuizId')->willReturn(1); + + $parserMock = $this->createMock(MarkdownParser::class); + $parserMock->expects(self::any())->method('parser')->willReturn($question); + + $quizGenerator = new QuestionGenerator($this->fetcherMock, $parserMock); $dataSets = $quizGenerator->generate(self::SOURCE); $question2 = $dataSets[1]; self::assertSame(1, $question2->getQuizId()); - self::assertSame('Style override', $question2->getTitle()); } public function testGeneratedTitle() { - $quizGenerator = new QuestionGenerator($this->fetcherMock); + $question = $this->createMock(Question::class); + $question->expects(self::once())->method('getTitle')->willReturn('Style override'); + + $parserMock = $this->createMock(MarkdownParser::class); + $parserMock->expects(self::any())->method('parser')->willReturn($question); + + $quizGenerator = new QuestionGenerator($this->fetcherMock, $parserMock); $dataSets = $quizGenerator->generate(self::SOURCE); $question2 = $dataSets[1]; diff --git a/api/tests/unit/src/Markdown/QuestionIDGeneratorTest.php b/api/tests/unit/src/Markdown/QuestionIDGeneratorTest.php index 8e51e6d..4f5ff18 100644 --- a/api/tests/unit/src/Markdown/QuestionIDGeneratorTest.php +++ b/api/tests/unit/src/Markdown/QuestionIDGeneratorTest.php @@ -3,6 +3,7 @@ namespace App\Tests\unit\src\Markdown; use App\Markdown\FetcherInterface; +use App\Markdown\Parser\MarkdownParser; use App\Markdown\QuestionGenerator; use PHPUnit\Framework\TestCase; @@ -11,7 +12,8 @@ class QuestionIDGeneratorTest extends TestCase public function testGetQuestionID() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $questionID = $generator->getIDFromFilePath('1_2_style_override.md', false); self::assertSame(2, $questionID); } @@ -19,7 +21,8 @@ public function testGetQuestionID() public function testGetQuestionIDWithDoubleDigits() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $questionID = $generator->getIDFromFilePath('1_20_style_override.md', false); self::assertSame(20, $questionID); } @@ -27,7 +30,8 @@ public function testGetQuestionIDWithDoubleDigits() public function testGetQuestionIDWithNoIDValue() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $questionID = $generator->getIDFromFilePath('1.md', false); self::assertFalse($questionID); } @@ -35,7 +39,9 @@ public function testGetQuestionIDWithNoIDValue() public function testGetQuestionIDWithIncorrectValueType() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); + $questionID = $generator->getIDFromFilePath('1_two.md', false); $questionID = $generator->getIDFromFilePath('1_two.md', false); self::assertFalse($questionID); } diff --git a/api/tests/unit/src/Markdown/QuestionQuizIDGeneratorTest.php b/api/tests/unit/src/Markdown/QuestionQuizIDGeneratorTest.php index 8e9a1c6..f161a33 100644 --- a/api/tests/unit/src/Markdown/QuestionQuizIDGeneratorTest.php +++ b/api/tests/unit/src/Markdown/QuestionQuizIDGeneratorTest.php @@ -3,6 +3,7 @@ namespace App\Tests\unit\src\Markdown; use App\Markdown\FetcherInterface; +use App\Markdown\Parser\MarkdownParser; use App\Markdown\QuestionGenerator; use PHPUnit\Framework\TestCase; @@ -11,7 +12,8 @@ class QuestionQuizIDGeneratorTest extends TestCase public function testGetQuestionID() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $ID = $generator->getIDFromFilePath('1_2_style_override.md'); self::assertSame(1, $ID); } @@ -19,7 +21,8 @@ public function testGetQuestionID() public function testGetQuestionIDWithDoubleDigits() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $ID = $generator->getIDFromFilePath('10_20_style_override.md'); self::assertSame(10, $ID); } @@ -27,7 +30,8 @@ public function testGetQuestionIDWithDoubleDigits() public function testGetQuestionIDWithNoIDValue() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $ID = $generator->getIDFromFilePath('foo.md'); self::assertFalse($ID); } @@ -35,7 +39,8 @@ public function testGetQuestionIDWithNoIDValue() public function testGetQuestionIDWithIncorrectValueType() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $ID = $generator->getIDFromFilePath('one_2.md'); self::assertFalse($ID); } diff --git a/api/tests/unit/src/Markdown/QuestionTitleGeneratorTest.php b/api/tests/unit/src/Markdown/QuestionTitleGeneratorTest.php index 65530f2..6d95dca 100644 --- a/api/tests/unit/src/Markdown/QuestionTitleGeneratorTest.php +++ b/api/tests/unit/src/Markdown/QuestionTitleGeneratorTest.php @@ -3,6 +3,7 @@ namespace App\Tests\unit\src\Markdown; use App\Markdown\FetcherInterface; +use App\Markdown\Parser\MarkdownParser; use App\Markdown\QuestionGenerator; use PHPUnit\Framework\TestCase; @@ -11,7 +12,8 @@ class QuestionTitleGeneratorTest extends TestCase public function testGetQuestionTitle() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $title = $generator->getTitleFromFilePath('1_2_style_override.md'); self::assertSame('Style override', $title); } @@ -19,7 +21,8 @@ public function testGetQuestionTitle() public function testGetQuestionTitleWithNoTitleValue() { $fetcherMock = $this->createMock(FetcherInterface::class); - $generator = new QuestionGenerator($fetcherMock); + $parserMock = $this->createMock(MarkdownParser::class); + $generator = new QuestionGenerator($fetcherMock, $parserMock); $title = $generator->getTitleFromFilePath('1.md'); self::assertFalse($title); }