Skip to content
Merged

Dev #18

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
project(server)

set(CMAKE_CXX_FLAGS "-std=c++17 -O3 -pedantic -Wall -Werror")
set(CMAKE_CXX_FLAGS "-std=c++17 -fsanitize=address -ggdb3 -Wall -Wextra -pedantic -Werror")

add_subdirectory(external)
add_subdirectory(common)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace parsers
class ICredentialsParser
{
public:
virtual ~ICredentialParser() = default;
virtual ~ICredentialsParser() = default;

virtual std::optional<types::User> parseCredentials(const std::string &) const = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion app/interfaces/include/interfaces/parsers/IReportParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace parsers
public:
virtual ~IReportParser() = default;

virtual std::optional<types::Report> parseRepost(const std::string &) const = 0;
virtual std::optional<types::Report> parseReport(const std::string &) const = 0;
};
}

Expand Down
8 changes: 8 additions & 0 deletions app/parsers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
project(Parsers)

add_subdirectory(test)

find_package(Boost REQUIRED)

include_directories(${Boost_INCLUDE_DIRS})

set(HEADERS
${PROJECT_SOURCE_DIR}/include/parsers/JsonParser.h
${PROJECT_SOURCE_DIR}/include/parsers/XmlParser.h
${PROJECT_SOURCE_DIR}/include/parsers/ParsersFactory.h
${PROJECT_SOURCE_DIR}/include/parsers/ValidatedReportParser.h
)


set(SOURCES
${PROJECT_SOURCE_DIR}/src/JsonParser.cpp
${PROJECT_SOURCE_DIR}/src/ParsersFactory.cpp
${PROJECT_SOURCE_DIR}/src/XmlParser.cpp
${PROJECT_SOURCE_DIR}/src/ValidatedReportParser.cpp
)

add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
Expand Down
2 changes: 1 addition & 1 deletion app/parsers/include/parsers/JsonParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace parsers
{
class JsonParser : public IReportParser, public ICredentialParser
class JsonParser : public IReportParser, public ICredentialsParser
{
public:
std::optional <types::Report> parseReport(const std::string &) const override;
Expand Down
8 changes: 8 additions & 0 deletions app/parsers/include/parsers/ParsersFactory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//
// Created by sajith on 6/21/22.
//

#ifndef DESIGN_PATTERNS_PARSERSFACTORY_H
#define DESIGN_PATTERNS_PARSERSFACTORY_H

#endif //DESIGN_PATTERNS_PARSERSFACTORY_H
8 changes: 8 additions & 0 deletions app/parsers/include/parsers/ValidatedReportParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//
// Created by sajith on 6/21/22.
//

#ifndef DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H
#define DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H

#endif //DESIGN_PATTERNS_VALIDATEDREPORTPARSER_H
14 changes: 14 additions & 0 deletions app/parsers/include/parsers/XmlParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,18 @@
#ifndef DESIGN_PATTERNS_XMLPARSER_H
#define DESIGN_PATTERNS_XMLPARSER_H


#include "parsers/ICredentialsParser.h"
#include "parsers/IReportParser.h"


namespace parsers
{
class XmlParser : public IReportParser, public ICredentialsParser
{
std::optional<types::Report> parseReport(const std::string &) const override;

std::optional<types::User> parseCredentials(const std::string &) const override;
};
}
#endif //DESIGN_PATTERNS_XMLPARSER_H
43 changes: 43 additions & 0 deletions app/parsers/src/JsonParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,46 @@

#include "parsers/JsonParser.h"

#include <iostream>
#include <stdexcept>

#include "nlohmann/json.hpp"

namespace parsers
{
std::optional<types::Report> JsonParser::parseReport(const std::string &rawReport) const try
{
if (const auto json = nlohmann::json::parse(rawReport); !json.empty())
{
return types::Report{
json.at("payer"),
json.at("tax"),
json.at("amount"),
json.at("year")};
}
return std::nullopt;
} catch (const std::exception &e)
{
std::cerr << __FILE__ << ' ' << e.what() << '\n';
return std::nullopt;
}

std::optional<types::User> JsonParser::parseCredentials(const std::string &rawCredentials) const try
{
if (const auto json = nlohmann::json::parse(rawCredentials); !json.empty())
{
return types::User
{
{json.at("login")},
{json.at("password")},
{}
};
}
return std::nullopt;

} catch (const std::exception &e)
{
std::cerr << __FILE__ << ' ' << e.what() << '\n';
return std::nullopt;
}
}
8 changes: 8 additions & 0 deletions app/parsers/src/ParsersFactory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//
// Created by sajith on 6/22/22.
//

#include "parsers/ParsersFactory.h"
#include "parsers/JsonParser.h"
#include "parsers/ValidatedReportParser.h"
#include "parsers/XmlParser.h"
16 changes: 16 additions & 0 deletions app/parsers/src/ValidatedReportParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Created by sajith on 6/21/22.
//

#include "parsers/ValidatedReportParser.h"

#include <chrono>
#include <ctime>
#include <iostream>
#include <stdexcept>

#include <boost/algorithm/string.hpp>

#include "constants/Constants.h"
#include "parsers/JsonParser.h"
#include "parsers/XmlParser.h"
72 changes: 72 additions & 0 deletions app/parsers/src/XmlParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// Created by sajith on 6/21/22.
//

#include "parsers/XmlParser.h"
#include "tinyxml2/tinyxml2.h"

#include <iostream>

#include <stdexcept>
#include <boost/lexical_cast.hpp>


namespace
{
template<typename T>
auto getFromXml(const tinyxml2::XMLNode *node, const char *field)
{
if (node == nullptr || node->FirstChildElement(field) == nullptr)
{
throw std::runtime_error{"Invalid XML!"};
}

return boost::lexical_cast<T>(node->FirstChildElement(field)->GetText());
}
}

namespace parsers
{
std::optional<types::Report> XmlParser::parseReport(const std::string &rawReport) const try
{
tinyxml2::XMLDocument doc;
doc.Parse(rawReport.data(), rawReport.length());
if (const tinyxml2::XMLNode *root = doc.FirstChild())
{
return types::Report
{
getFromXml<std::uint32_t>(root, "payer"),
getFromXml<std::string>(root, "tax"),
getFromXml<double>(root, "amount"),
getFromXml<std::uint16_t>(root, "year")
};
}

return std::nullopt;
} catch (const std::exception &e)
{
std::cerr << __FILE__ << ' ' << e.what() << '\n';
return std::nullopt;
}

std::optional<types::User> XmlParser::parseCredentials(const std::string &rawCredentials) const try
{
tinyxml2::XMLDocument doc;
doc.Parse(rawCredentials.data(), rawCredentials.length());

if (tinyxml2::XMLNode *root = doc.FirstChild())
{
return types::User
{
{getFromXml<std::string>(root, "login")},
{getFromXml<std::string>(root, "password")},
{}
};
}
return std::nullopt;
} catch (const std::exception &e)
{
std::cerr << __FILE__ << ' ' << e.what() << '\n';
return std::nullopt;
}
}
21 changes: 21 additions & 0 deletions app/parsers/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
project(ParsersTests)

find_package(GTest REQUIRED)

include_directories(${GTEST_INCLUDE_DIR})

set(SOURCES
JsonParser_test.cpp
)

add_executable(${PROJECT_NAME} ${SOURCES})

target_link_libraries(${PROJECT_NAME} PRIVATE
GTest::GTest
GTest::Main
Interfaces
External
Common
Parsers)

add_test(${PROJECT_NAME} ${PROJECT_NAME})
71 changes: 71 additions & 0 deletions app/parsers/test/JsonParser_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// Created by sajith on 6/22/22.
//

#include "parsers/JsonParser.h"

#include <gtest/gtest.h>
#include <optional>

#include "nlohmann/json.hpp"
#include "types/Report.h"

using json = nlohmann::json;

struct JsonParserTests : testing::Test
{
parsers::JsonParser sut;
};


TEST_F(JsonParserTests, WhenValidData_parseReturnRepor)
{
const json jsonReport = {{"payer", 1},
{"tax", "VAT"},
{"amount", 1000},
{"year", 2020}};

const std::optional<types::Report> parsedReport = sut.parseReport(to_string(jsonReport));
const types::Report expectedReport{1, "VAT", 1000, 2020};
ASSERT_TRUE(parsedReport);
ASSERT_EQ(parsedReport, expectedReport);
}

TEST_F(JsonParserTests, WhenMissingFields_parseReportReturnNull)
{
const json jsonReport{{"payer", 1},
{"year", 2020}};
ASSERT_EQ(sut.parseReport(nlohmann::to_string(jsonReport)), std::nullopt);
}

TEST_F(JsonParserTests, whenNumericDataInvalid_parseReportReturnsNull)
{
const json jsonReport = {{"payer", "one"},
{"tax", "VAT"},
{"amount", "Ten"},
{"year", "Thousand"}};
ASSERT_EQ(sut.parseReport(nlohmann::to_string(jsonReport)), std::nullopt);
}

TEST_F(JsonParserTests, whenValidData_parseCredentialsReturnsUser)
{
const types::User user{{"Jhon Doe"},
{"Password"},
{}};

const json jsonCreds = {{"login", user.login.value},
{"password", user.password.value}};

const std::optional<types::User> parsedUser = sut.parseCredentials(to_string(jsonCreds));

ASSERT_TRUE(parsedUser);
ASSERT_EQ(parsedUser->login.value, user.login.value);
ASSERT_EQ(parsedUser->password.value, user.password.value);
}

TEST_F(JsonParserTests, whenMissingFields_parseCredentialsReturnsNull)
{
const json jsonCreds = {{"login", "Jhon Doe"}};
ASSERT_EQ(sut.parseCredentials(to_string(jsonCreds)), std::nullopt);
}