diff --git a/src/test/transpilerFunctional.cpp b/src/test/transpilerFunctional.cpp index 48b1113..9c36917 100644 --- a/src/test/transpilerFunctional.cpp +++ b/src/test/transpilerFunctional.cpp @@ -287,18 +287,53 @@ TEST(TranspilerTest, TestOrderQuestionDuplicates) { } TEST(TranspilerTest, TestRemovesExcessiveWhitespace) { - std::string questionText = "- \n\t A question\n\t front\n\t >\n" - "-\n\t An\n\t answer\n\t " - "-\n\t Another\n\t answer\n\t "; + std::string questionText = + "- \n\t Question \n\t 1 \n\t >\n" + "-\n\t An\n\t answer\n\t " + "-\n\t Another\n\t answer\n\t " + "- \n\t Question \n\t 2 \n\t >\n" + "-\n\t Element\n\t 1\n\t " + "-\n\t ^ \n\t Element\n\t 2\n\t " + "- \n\t Question \n\t 3 \n\t >\n" + "+\n\t An\n\t answer\n\t " + "-\n\t Another\n\t answer\n\t " + "+\n\t Yet another\n\t answer\n\t " + "- \n\t Question \n\t 4 \n\t >\n" + "-\n\t A\n\t group \n\t :\n\t " + "-\n\t Group\n\t 1\n\t " + "-\n\t Group\n\t 2\n\t " + "-\n\t Group\n\t 3\n\t "; auto res = transpile(questionText); auto questions = res.value.questions; - EXPECT_EQ(questions[0]->questionText, "A question front"); + EXPECT_EQ(questions[0]->questionText, "Question 1"); + EXPECT_EQ(questions[1]->questionText, "Question 2"); + EXPECT_EQ(questions[2]->questionText, "Question 3"); + EXPECT_EQ(questions[3]->questionText, "Question 4"); auto meQuestion = dynamic_cast(questions[0]); EXPECT_EQ(meQuestion->choices[0].answer, "An answer"); EXPECT_EQ(meQuestion->choices[1].answer, "Another answer"); + + auto ordQuestion = dynamic_cast(questions[1]); + EXPECT_EQ(ordQuestion->choices[0].answer, "Element 1"); + EXPECT_EQ(ordQuestion->choices[1].answer, "Element 2"); + + auto choiceQuestion = dynamic_cast(questions[2]); + EXPECT_EQ(choiceQuestion->choices[0].answer, "An answer"); + EXPECT_EQ(choiceQuestion->choices[1].answer, "Another answer"); + EXPECT_EQ(choiceQuestion->choices[2].answer, "Yet another answer"); + + auto groupQuestion = dynamic_cast(questions[3]); + EXPECT_EQ(groupQuestion->groups[0].name, "A group"); + EXPECT_EQ(groupQuestion->groups[0].elements[0], "Group 1"); + EXPECT_EQ(groupQuestion->groups[0].elements[1], "Group 2"); + EXPECT_EQ(groupQuestion->groups[0].elements[2], "Group 3"); + delete meQuestion; + delete ordQuestion; + delete choiceQuestion; + delete groupQuestion; } TEST(TranspilerTest, TestTranspilesMultipleQuestions) { @@ -361,3 +396,53 @@ TEST(TranspilerTest, TestTranspilesMultipleQuestions) { EXPECT_EQ(group.elements[1], "Element 2"); delete groupQuestion; } + +TEST(TranspilerTest, TestTranspilesDatetime) { + std::string questionText = "01.01.2024 02\\:03 - question > - ioewjfwe"; + auto res = transpile(questionText); + ASSERT_EQ(res.value.lastTrainedAt, 1704074580); + EXPECT_EQ(res.error, ""); + + questionText = "1.1.2024 2\\:3"; + res = transpile(questionText); + ASSERT_EQ(res.value.lastTrainedAt, 1704074580); + EXPECT_EQ(res.error, ""); + + questionText = + "\n\t 01.01.2024 " + " \t\n\n\t " + " \n\t 02\\:03"; + res = transpile(questionText); + ASSERT_EQ(res.value.lastTrainedAt, 1704074580); + EXPECT_EQ(res.error, ""); +} + +TEST(TranspilerTest, TestIncorrectDatetime) { + std::string questionText; + auto checkIsError = [](std::string questionText) { + auto res = transpile(questionText); + EXPECT_NE(res.error, ""); + }; + + questionText = "01 .01.2024 02\\:03"; + checkIsError(questionText); + questionText = "01. 01.2024 02\\:03"; + checkIsError(questionText); + questionText = "01.01. 2024 02\\:03"; + checkIsError(questionText); + questionText = "01.01.2024 02 \\:03"; + checkIsError(questionText); + questionText = "01.01.2024 02\\: 03"; + checkIsError(questionText); + + questionText = "001.01.2024 02\\:03"; + checkIsError(questionText); + questionText = "01.001.2024 02\\:03"; + checkIsError(questionText); + questionText = "01.01.20024 02\\:03"; + checkIsError(questionText); + questionText = "01.01.2024 002\\:03"; + checkIsError(questionText); + questionText = "01.01.2024 02\\:003"; + checkIsError(questionText); +} diff --git a/src/transpiler/parser.cpp b/src/transpiler/parser.cpp index 577501b..1b08191 100644 --- a/src/transpiler/parser.cpp +++ b/src/transpiler/parser.cpp @@ -153,8 +153,23 @@ Result parseQuestions(const std::vector& tokens) { // Sākuma datumu un laiku mēģina nolasīt, ja tāds ir norādīts. if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) { + + // Pārbauda datuma un laika formātu. + auto datetimeContent = cleanContent(tokens[i].content); + static const std::regex datetimeExp( + "^\\d\\d?\\.\\d\\d?\\.\\d\\d\\d\\d \\d\\d?:\\d\\d?$", + std::regex_constants::ECMAScript | std::regex_constants::icase + ); + if (!std::regex_match(datetimeContent, datetimeExp)) { + return makeResult( + "Nekorekts datuma un laika formāts", + tokens[i] + ); + } + + // Parsē datumu un laiku. const std::string format = "%d.%m.%Y %H:%M"; - const std::string datetime = tokens[i].content.c_str(); + const std::string datetime = datetimeContent.c_str(); std::tm tm = {}; std::istringstream ss(datetime); ss >> std::get_time(&tm, format.c_str()); @@ -192,12 +207,13 @@ Result parseQuestions(const std::vector& tokens) { questionStartToken = tokens[i]; // Apstrādā pārtraukumu, ja tāds ir. + bool hasCooldown; if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::CooldownStart) { try { auto cooldownContent = tokens[i + 2].content; // Pārbauda, vai dotais pārtraukums ir viens skaitlis, kas ir: // - pozitīvs; - // - viens no: vesels skaitlis vai ar punktu atdalīts skatilis + // - viens no: vesels skaitlis vai ar punktu atdalīts skaitlis // ar norādīto vai bez norādītās veselās daļas. static const std::regex decimalNumExp( "^\\d*(\\.\\d+)?$", @@ -215,13 +231,24 @@ Result parseQuestions(const std::vector& tokens) { ); } questionText = tokens[i + 4].content; - i += 6; + hasCooldown = true; } else { cooldown = 0; questionText = tokens[i + 1].content; - i += 3; + hasCooldown = false; } + int questionStartOffset = hasCooldown ? 5 : 2; + // Pārbauda, vai jautājums ir nobeigts ar korektu simbolu. + if (isInBounds(questionStartOffset) && + tokens[i + questionStartOffset].tokenType != TokenType::QuestionEnd) { + return makeResult( + "Jautājumu var iesākt tikai ar \">\"", + tokens[i + questionStartOffset] + ); + } + i += hasCooldown ? 6 : 3; + // Jautājumu elementu parsēšana. while (isInBounds(i)) { @@ -352,7 +379,7 @@ Result parseQuestions(const std::vector& tokens) { if (isGroupQuestion) { auto *question = new GroupQuestion(); question->cooldown = cooldown; - question->questionText = questionText; + question->questionText = cleanContent(questionText); // Izveido grupas; i - elementu iterators; k - grupu iterators. int32_t k = -1;