Skip to content

Commit d8a57a1

Browse files
authored
Merge pull request #19 from snandasena/dev
Imoproved
2 parents 9197911 + b0f48bd commit d8a57a1

File tree

8 files changed

+203
-6
lines changed

8 files changed

+203
-6
lines changed

app/common/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ set(SOURCES
1717

1818
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
1919

20-
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/inc;include)
20+
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)

app/common/include/constants/Constants.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@
1010

1111
namespace constants
1212
{
13-
std::string OK{"OK"};
14-
std::string NOK{"NOK"};
15-
16-
const std::unordered_set<std::string> validTaxNames{
13+
const std::string OK{"OK"};
14+
const std::string NOK{"NOK"};
15+
// clang-format off
16+
const std::unordered_set<std::string> validTaxNames = {
1717
"corporate income tax",
1818
"individual income tax",
1919
"value added tax",
2020
"withholding tax"
2121
"property tax",
2222
"exit tax"
2323
};
24+
// clang-format on
2425
}
2526

2627
#endif //DESIGN_PATTERNS_CONSTANTS_H

app/parsers/include/parsers/ValidatedReportParser.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,21 @@
55
#ifndef DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H
66
#define DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H
77

8+
#include "parsers/IReportParser.h"
9+
10+
#include <type_traits>
11+
12+
13+
namespace parsers
14+
{
15+
template<typename BaseReportParser>
16+
class ValidatedReportParser : public BaseReportParser
17+
{
18+
public:
19+
static_assert(std::is_base_of<IReportParser, BaseReportParser>::value);
20+
21+
std::optional<types::Report> parseReport(const std::string &) const override;
22+
};
23+
}
24+
825
#endif //DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H

app/parsers/include/parsers/XmlParser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace parsers
1414
{
1515
class XmlParser : public IReportParser, public ICredentialsParser
1616
{
17+
public:
18+
1719
std::optional<types::Report> parseReport(const std::string &) const override;
1820

1921
std::optional<types::User> parseCredentials(const std::string &) const override;

app/parsers/src/ValidatedReportParser.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,51 @@
1313

1414
#include "constants/Constants.h"
1515
#include "parsers/JsonParser.h"
16-
#include "parsers/XmlParser.h"
16+
#include "parsers/XmlParser.h"
17+
18+
namespace
19+
{
20+
bool validateTaxYear(const types::Report &report)
21+
{
22+
using Clock = std::chrono::system_clock;
23+
24+
const auto now = Clock::now();
25+
const std::time_t now_c = Clock::to_time_t(now);
26+
const struct tm *parts = std::localtime(&now_c);
27+
28+
const auto currentyear = 1900 + parts->tm_year;
29+
return report.year <= currentyear;
30+
}
31+
}
32+
33+
namespace parsers
34+
{
35+
template<typename BaseReportParser>
36+
std::optional<types::Report> ValidatedReportParser<BaseReportParser>::parseReport(const std::string &rawReport)
37+
const try
38+
{
39+
if (const auto report = BaseReportParser::parseReport(rawReport))
40+
{
41+
if (report->amount > 0.0 && validateTaxYear(*report))
42+
{
43+
std::string tax = report->tax;
44+
boost::algorithm::to_lower(tax);
45+
if (constants::validTaxNames.count(tax))
46+
{
47+
return report;
48+
}
49+
}
50+
}
51+
return std::nullopt;
52+
} catch (const std::exception &e)
53+
{
54+
std::cerr << __FILE__ << ' ' << e.what() << '\n';
55+
return std::nullopt;
56+
}
57+
58+
template
59+
class ValidatedReportParser<JsonParser>;
60+
61+
template
62+
class ValidatedReportParser<XmlParser>;
63+
}

app/parsers/test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ include_directories(${GTEST_INCLUDE_DIR})
66

77
set(SOURCES
88
JsonParser_test.cpp
9+
XmlParser_test.cpp
10+
ValidatedReportParser_tests.cpp
911
)
1012

1113
add_executable(${PROJECT_NAME} ${SOURCES})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// Created by sajith on 6/22/22.
3+
//
4+
5+
#include "parsers/ValidatedReportParser.h"
6+
7+
#include <gtest/gtest.h>
8+
#include <optional>
9+
#include <string>
10+
#include <vector>
11+
12+
#include "constants/Constants.h"
13+
#include "nlohmann/json.hpp"
14+
#include "parsers/JsonParser.h"
15+
#include "parsers/XmlParser.h"
16+
#include "types/Report.h"
17+
18+
using json = nlohmann::json;
19+
20+
namespace parsers
21+
{
22+
struct ValidatedReportParserTest : testing::Test
23+
{
24+
const ValidatedReportParser<JsonParser> sut;
25+
const std::string taxName = *constants::validTaxNames.begin();
26+
27+
const std::string validReport =
28+
nlohmann::to_string(json{{"payer", 1},
29+
{"tax", taxName},
30+
{"amount", 1000},
31+
{"year", 2020}});
32+
33+
const std::vector<std::string> invalidReports = {
34+
to_string(json{{"payer", 1},
35+
{"tax", taxName},
36+
{"amount", 0.0},
37+
{"year", 2020}}),
38+
to_string(json{{"payer", 1},
39+
{"tax", taxName},
40+
{"amount", 1000},
41+
{"year", 2222}}),
42+
to_string(json{{"payer", 1},
43+
{"tax", "Unknown tax"},
44+
{"amount", 0},
45+
{"year", 2020}}),
46+
};
47+
};
48+
49+
TEST_F(ValidatedReportParserTest, reportValidationSucceeds)
50+
{
51+
// ASSERT_NE(sut.parseReport(validReport), std::nullopt);
52+
}
53+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// Created by sajith on 6/22/22.
3+
//
4+
5+
#include "parsers/XmlParser.h"
6+
7+
#include <gtest/gtest.h>
8+
#include <optional>
9+
#include <string>
10+
11+
#include "types/Report.h"
12+
13+
struct XmlParserTest : testing::Test
14+
{
15+
parsers::XmlParser sut;
16+
};
17+
18+
TEST_F(XmlParserTest, whenValidData_parseReportReturnsReport)
19+
{
20+
const std::string xmlRequest{"<report>"
21+
"<payer>2</payer>"
22+
"<tax>VAT</tax>"
23+
"<amount>10</amount>"
24+
"<year>2020</year>"
25+
"</report>"};
26+
27+
const std::optional<types::Report> parserReport = sut.parseReport(xmlRequest);
28+
const types::Report expectedReport{2, "VAT", 10, 2020};
29+
ASSERT_TRUE(parserReport);
30+
ASSERT_EQ(parserReport, expectedReport);
31+
}
32+
33+
34+
35+
TEST_F(XmlParserTest, whenMissingFields_parseReportReturnsNull)
36+
{
37+
const std::string xmlReport = "<report><payer>2</payer><year>2020</year></report>";
38+
ASSERT_EQ(sut.parseReport(xmlReport), std::nullopt);
39+
}
40+
41+
TEST_F(XmlParserTest, whenEmptyReport_parseReportReturnsNull)
42+
{
43+
const std::string xmlReport = "";
44+
ASSERT_EQ(sut.parseReport(xmlReport), std::nullopt);
45+
}
46+
47+
TEST_F(XmlParserTest, whenInvalidXml_parseReportReturnsNull)
48+
{
49+
const std::string xmlReport = "<<report>>";
50+
ASSERT_EQ(sut.parseReport(xmlReport), std::nullopt);
51+
}
52+
53+
TEST_F(XmlParserTest, whenNumericDataInvalid_parseReportReturnsNull)
54+
{
55+
const std::string xmlReport = "<report><payer>Two</payer><tax>VAT</tax><amount>One"
56+
"</amount><year>Three</year></report>";
57+
ASSERT_EQ(sut.parseReport(xmlReport), std::nullopt);
58+
}
59+
60+
TEST_F(XmlParserTest, whenValidData_parseCredentialsReturnsUser)
61+
{
62+
const std::string xmlReport = "<credentials><login>Jhon Doe</login>"
63+
"<password>123</password></credentials>";
64+
const std::optional<types::User> parsedUser = sut.parseCredentials(xmlReport);
65+
ASSERT_TRUE(parsedUser);
66+
ASSERT_EQ(parsedUser->login.value, std::string("Jhon Doe"));
67+
ASSERT_EQ(parsedUser->password.value, std::string("123"));
68+
}
69+
70+
TEST_F(XmlParserTest, whenMissingFields_parseCredentialsReturnsNull)
71+
{
72+
const std::string xmlReport = "<credentials><login>Jhon Doe</login></credentials>";
73+
const std::optional<types::User> parsedUser = sut.parseCredentials(xmlReport);
74+
ASSERT_EQ(parsedUser, std::nullopt);
75+
}

0 commit comments

Comments
 (0)