diff --git a/CMakeLists.txt b/CMakeLists.txt index e6318a3..ac1d32d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,12 @@ cmake_minimum_required(VERSION 3.5.1) project(dummy_cmake_project) set(CMAKE_CXX_STANDARD 14) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -set(SOURCES project.cc) +set(SOURCES project.cc constant.h project_operation.h project_operation.cpp) add_library(ProjectLib ${SOURCES}) add_executable(project main.cc) diff --git a/README.md b/README.md new file mode 100644 index 0000000..92f0e83 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Polish_notation \ No newline at end of file diff --git a/constant.h b/constant.h new file mode 100644 index 0000000..55b8409 --- /dev/null +++ b/constant.h @@ -0,0 +1,24 @@ +#ifndef CONSTANT +#define CONSTANT + +#include +#include + +namespace polish_notation_constant +{ + typedef double value_t; + typedef std::stack stack_numbers_t; + + constexpr value_t ERROR_VALUE = std::numeric_limits::max(); + + enum class error_code { + STACK_EMPTY, + NOT_CORRECT_EXPRESSION, + ZERO_DEVISION, + NO_ERROR, + NOT_CORRECT_COUNT_OF_OPERATION + }; +} + +#endif // CONSTANT + diff --git a/iproject.h b/iproject.h index ec4452f..0392514 100644 --- a/iproject.h +++ b/iproject.h @@ -1,9 +1,10 @@ #pragma once +#include namespace dev{ class IProject { - virtual int run() = 0; + virtual double run(std::string) = 0; }; } diff --git a/main.cc b/main.cc index 5b2357f..d1bf243 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,21 @@ #include "project.h" +#include "constant.h" +#include +#include -int main() { - return 0; +int main() +{ + dev::Project project; + auto value = project.run("2 2 +"); + + if( value != polish_notation_constant::ERROR_VALUE) + { + std::cout << "Result: " << value << std::endl; + } + else + { + std::cout << "Error code: " << project.get_error_code() << std::endl; + } + + return 0; } diff --git a/project.cc b/project.cc index fdc1225..072e827 100644 --- a/project.cc +++ b/project.cc @@ -2,7 +2,133 @@ namespace dev { -int Project::run() { - return 0; + +value_t Project::run(std::string input_str) { + + return processData(input_str); +} + + +bool Project::is_valid_count_value(stack_numbers_t& stack) +{ + if (stack.size() < 2) { + error_code_val = error_code::NOT_CORRECT_COUNT_OF_OPERATION; + + return false; + } + else + { + return true; + } +} + +value_t Project::take_value_from_stack(stack_numbers_t& stack) +{ + value_t value = ERROR_VALUE; + + if (stack.size() != 0) { + value = stack.top(); + stack.pop(); + } + else{ + error_code_val = error_code::STACK_EMPTY; + } + + return value; +} + + + +bool Project::is_number(const std::string& s) +{ + char* end = 0; + double val = std::strtod(s.c_str(), &end); + return end != s.c_str() && *end == '\0' && val != HUGE_VAL; +} + +void Project::clear_stack(stack_numbers_t & stack) +{ + while(!stack.empty()) + { + stack.pop(); + } +} + +int Project::get_error_code() +{ + return static_cast(error_code_val); +} + +value_t Project::calculateStackValue(std::string temp_str, stack_numbers_t& stack_numbers) +{ + double left_operand, right_operand; + + right_operand = take_value_from_stack(stack_numbers); + left_operand = take_value_from_stack(stack_numbers); + + left_operand = project_operation_.make_operation(temp_str[0], left_operand, right_operand); + + if(left_operand == ERROR_VALUE) + { + error_code_val = error_code::NOT_CORRECT_EXPRESSION; + return ERROR_VALUE; + } + + if(left_operand != polish_notation_constant::ERROR_VALUE && temp_str[0] == '/') { + error_code_val = error_code::ZERO_DEVISION; + } + + return left_operand; +} + +value_t Project::processData(std::string& input_str) +{ + stack_numbers_t stack_numbers; + error_code_val = error_code::NO_ERROR; + + value_t return_value = ERROR_VALUE; + std::istringstream f(input_str); + std::string temp_str; + + + while (std::getline(f, temp_str, ' ')) { + std::cout << "Stack value: " << temp_str << std::endl; + + if(is_number(temp_str)) { + stack_numbers.push(std::stod(temp_str.c_str())); + } + else { + if (true == is_valid_count_value(stack_numbers)) { + value_t value = calculateStackValue(temp_str, stack_numbers); + + if (value != ERROR_VALUE){ + stack_numbers.push(value); + } + else{ + break; + } + + } else { + error_code_val = error_code::NOT_CORRECT_COUNT_OF_OPERATION; + } + } + + if(error_code_val != error_code::NO_ERROR) { + clear_stack(stack_numbers); + break; + } + } + + + if (input_str.empty()) + { + error_code_val = error_code::STACK_EMPTY; + } + + if (stack_numbers.size() != 0) { + return_value = stack_numbers.top(); + } + + return return_value; } } // namespace dev diff --git a/project.cc.autosave b/project.cc.autosave new file mode 100644 index 0000000..319eec4 --- /dev/null +++ b/project.cc.autosave @@ -0,0 +1,134 @@ +#include "project.h" + +namespace dev { + + +value_t Project::run(std::string input_str) { + + return processData(input_str); +} + + +bool Project::is_valid_count_value(stack_numbers_t& stack) +{ + if (stack.size() < 2) { + error_code_val = error_code::NOT_CORRECT_COUNT_OF_OPERATION; + + return false; + } + else + { + return true; + } +} + +value_t Project::take_value_from_stack(stack_numbers_t& stack) +{ + value_t value = ERROR_VALUE; + + if (stack.size() != 0) { + value = stack.top(); + stack.pop(); + } + else{ + error_code_val = error_code::STACK_EMPTY; + } + + return value; +} + + + +bool Project::is_number(const std::string& s) +{ + char* end = 0; + double val = std::strtod(s.c_str(), &end); + return end != s.c_str() && *end == '\0' && val != HUGE_VAL; +} + +void Project::clear_stack(stack_numbers_t & stack) +{ + while(!stack.empty()) + { + stack.pop(); + } +} + +int Project::get_error_code() +{ + return static_cast(error_code_val); +} + +value_t Project::calculateStackValue(std::string temp_str, stack_numbers_t& stack_numbers) +{ + double left_operand, right_operand; + + right_operand = take_value_from_stack(stack_numbers); + left_operand = take_value_from_stack(stack_numbers); + + left_operand = project_operation_.make_operation(temp_str[0], left_operand, right_operand); + + if(left_operand == ERROR_VALUE) + { + error_code_val = error_code::NOT_CORRECT_EXPRESSION; + return ERROR_VALUE; + } + + if(left_operand != polish_notation_constant::ERROR_VALUE && temp_str[0] == '/') { + error_code_val = error_code::ZERO_DEVISION; + } + + return left_operand; +} + +value_t Project::processData(std::string& input_str) +{ + stack_numbers_t stack_numbers; + error_code_val = error_code::NO_ERROR; + + value_t return_value = ERROR_VALUE; + std::istringstream f(input_str); + std::string temp_str; + + + while (std::getline(f, temp_str, ' ')) { + std::cout << "Stack value: " << temp_str << std::endl; + + if(is_number(temp_str)) { + stack_numbers.push(std::stod(temp_str.c_str())); + } + else { + if (is_valid_count_value(stack_numbers) == true) { + value_t value = calculateStackValue(temp_str, stack_numbers); + + if (value != ERROR_VALUE){ + stack_numbers.push(value); + } + else{ + break; + } + + } else { + error_code_val = error_code::NOT_CORRECT_COUNT_OF_OPERATION; + } + } + + if(error_code_val != error_code::NO_ERROR) { + clear_stack(stack_numbers); + break; + } + } + + + if (input_str.empty()) + { + error_code_val = error_code::STACK_EMPTY; + } + + if (stack_numbers.size() != 0) { + return_value = stack_numbers.top(); + } + + return return_value; +} +} // namespace dev diff --git a/project.h b/project.h index b5cc813..022971d 100644 --- a/project.h +++ b/project.h @@ -1,11 +1,43 @@ #pragma once #include "iproject.h" +#include "constant.h" +#include "project_operation.h" + +#include +#include +#include +#include +#include +#include + namespace dev { +using namespace polish_notation_constant; + + class Project : public IProject { - // IProject interface + typedef error_code error_t; + + // IProject interface public: - int run(); + double run(std::string); + + int get_error_code(); + +private: + void clear_stack(stack_numbers_t&); + value_t calculateStackValue(std::string temp_str, stack_numbers_t& stack_numbers); + + value_t take_value_from_stack(); + value_t processData(std::string& input_str); + value_t take_value_from_stack(stack_numbers_t&); + + bool is_valid_count_value(stack_numbers_t&); + bool is_number(const std::string& s); + + + project_operation project_operation_; + error_t error_code_val = error_code::NO_ERROR; }; } // namespace dev diff --git a/project_operation.cpp b/project_operation.cpp new file mode 100644 index 0000000..0bb9de6 --- /dev/null +++ b/project_operation.cpp @@ -0,0 +1,55 @@ +#include "project_operation.h" + +project_operation::project_operation() +{ + +} + +value_t project_operation::division(double a, double b) +{ + if (b != 0) { + return a / b; + } else { + return polish_notation_constant::ERROR_VALUE; + } +} + +value_t project_operation::sum(double a, double b) +{ + return a + b; +} + +value_t project_operation::subtract(double a, double b) +{ + return a - b; +} + +value_t project_operation::multiplication(double a, double b) +{ + return a * b; +} + +value_t project_operation::make_operation(char type_operation, + double left_operand, + double right_operand) +{ + switch(type_operation) { + case '+': + left_operand = sum(left_operand, right_operand); + break; + case '-': + left_operand = subtract(left_operand, right_operand); + break; + case '*': + left_operand = multiplication(left_operand, right_operand); + break; + case '/': + left_operand = division(left_operand, right_operand); + break; + default: + left_operand = ERROR_VALUE; + break; + } + + return left_operand; +} diff --git a/project_operation.h b/project_operation.h new file mode 100644 index 0000000..cfe9455 --- /dev/null +++ b/project_operation.h @@ -0,0 +1,23 @@ +#ifndef PROJECT_OPERATION_H +#define PROJECT_OPERATION_H +#include "constant.h" + +using namespace polish_notation_constant; + +class project_operation +{ + +public: + project_operation(); + + value_t make_operation(char type_operation, + double left_operand, + double right_operand); + + value_t division (double, double); + value_t sum (double, double); + value_t subtract (double, double); + value_t multiplication (double, double); +}; + +#endif // PROJECT_OPERATION_H diff --git a/test/project_test.cc b/test/project_test.cc index 5dbeb2f..e081556 100644 --- a/test/project_test.cc +++ b/test/project_test.cc @@ -1,4 +1,5 @@ #include "project.h" +#include "constant.h" #include #include namespace dev { @@ -11,8 +12,91 @@ class ProjectTest : public ::testing::Test { dev::Project project_; }; -TEST_F(ProjectTest, Run) { - ASSERT_EQ(0, project_.run()); +TEST_F(ProjectTest, Run_int) { + ASSERT_EQ(3, project_.run("1 2 +")); +} + +TEST_F(ProjectTest, Run_double) { + ASSERT_EQ(3.3, project_.run("1.3 2 +")); +} + +TEST_F(ProjectTest, Run_long_expression_below_zero) { + ASSERT_EQ(-1, project_.run("1 2 - 1 + 1 -")); +} + +TEST_F(ProjectTest, Run_long_expression_below_complex_test) { + ASSERT_EQ(21, project_.run("1 2 + 3 4 + *")); +} + +TEST_F(ProjectTest, Run_long_expression_above_zero) { + ASSERT_EQ(49, project_.run("1 2 + 4 + 7 *")); +} + +//TEST_F(ProjectTest, Is_number_double) { +// ASSERT_EQ(true, project_.is_number("1.3")); +//} + +//TEST_F(ProjectTest, Is_number_int) { +// ASSERT_EQ(true, project_.is_number("2")); +//} + +//TEST_F(ProjectTest, Is_number_invalid) { +// ASSERT_EQ(false, project_.is_number("asdas")); +//} + +//TEST_F(ProjectTest, Sum_double) { +// ASSERT_EQ(3.1, project_.sum(1.1, 2)); +//} + +//TEST_F(ProjectTest, Sum_int) { +// ASSERT_EQ(5, project_.sum(2, 3)); +//} + +//TEST_F(ProjectTest, Devision_double) { +// ASSERT_EQ(1.3, project_.division(2.6, 2)); +//} + +//TEST_F(ProjectTest, Devision_int) { +// ASSERT_EQ(3, project_.division(6, 2)); +//} + +//TEST_F(ProjectTest, Devision_zero_devision) { +// ASSERT_EQ(-1, project_.division(6, 0)); +//} + +//TEST_F(ProjectTest, Subtract_int) { +// ASSERT_EQ(4, project_.subtract(6, 2)); +//} + +//TEST_F(ProjectTest, Subtract_double) { +// ASSERT_EQ(4.2, project_.subtract(6.2, 2)); +//} + +//TEST_F(ProjectTest, Multiplication_double) { +// ASSERT_EQ(2.4, project_.multiplication(1.2, 2)); +//} + +//TEST_F(ProjectTest, Multiplication_int) { +// ASSERT_EQ(4, project_.multiplication(2, 2)); +//} + +// to do: test all error code output from project +TEST_F(ProjectTest, Run_error_code_test_NOT_CORRECT_COUNT_OF_OPERATION) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("+ +")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::NOT_CORRECT_COUNT_OF_OPERATION), + project_.get_error_code()); +} + +TEST_F(ProjectTest, Run_error_code_test_STACK_EMPTY) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::STACK_EMPTY), + project_.get_error_code()); +} + +TEST_F(ProjectTest, Run_error_code_test_STACK_NOT_CORRECT_EXPRESSION) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("2 3 &")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::NOT_CORRECT_EXPRESSION), + project_.get_error_code()); } } // namespace testing diff --git a/test/project_test.cc.autosave b/test/project_test.cc.autosave new file mode 100644 index 0000000..edd1eb7 --- /dev/null +++ b/test/project_test.cc.autosave @@ -0,0 +1,103 @@ +#include "project.h" +#include "constant.h" +#include +#include +namespace dev { +namespace testing { + +class ProjectTest : public ::testing::Test { + public: + void SetUp() override {} + void TearDown() override {} + dev::Project project_; +}; + +TEST_F(ProjectTest, Run_int) { + ASSERT_EQ(3, project_.run("1 2 +")); +} + +TEST_F(ProjectTest, Run_double) { + ASSERT_EQ(3.3, project_.run("1.3 2 +")); +} + +TEST_F(ProjectTest, Run_long_expression_below_zero) { + ASSERT_EQ(-1, project_.run("1 2 - 1 + 1 -")); +} + +TEST_F(ProjectTest, Run_long_expression_complex_test) { + ASSERT_EQ(21, project_.run("1 2 + 3 4 + *")); +} + +TEST_F(ProjectTest, Run_long_expression_above_zero) { + ASSERT_EQ(49, project_.run("1 2 + 4 + 7 *")); +} + +//TEST_F(ProjectTest, Is_number_double) { +// ASSERT_EQ(true, project_.is_number("1.3")); +//} + +//TEST_F(ProjectTest, Is_number_int) { +// ASSERT_EQ(true, project_.is_number("2")); +//} + +//TEST_F(ProjectTest, Is_number_invalid) { +// ASSERT_EQ(false, project_.is_number("asdas")); +//} + +//TEST_F(ProjectTest, Sum_double) { +// ASSERT_EQ(3.1, project_.sum(1.1, 2)); +//} + +//TEST_F(ProjectTest, Sum_int) { +// ASSERT_EQ(5, project_.sum(2, 3)); +//} + +//TEST_F(ProjectTest, Devision_double) { +// ASSERT_EQ(1.3, project_.division(2.6, 2)); +//} + +//TEST_F(ProjectTest, Devision_int) { +// ASSERT_EQ(3, project_.division(6, 2)); +//} + +//TEST_F(ProjectTest, Devision_zero_devision) { +// ASSERT_EQ(-1, project_.division(6, 0)); +//} + +//TEST_F(ProjectTest, Subtract_int) { +// ASSERT_EQ(4, project_.subtract(6, 2)); +//} + +//TEST_F(ProjectTest, Subtract_double) { +// ASSERT_EQ(4.2, project_.subtract(6.2, 2)); +//} + +//TEST_F(ProjectTest, Multiplication_double) { +// ASSERT_EQ(2.4, project_.multiplication(1.2, 2)); +//} + +//TEST_F(ProjectTest, Multiplication_int) { +// ASSERT_EQ(4, project_.multiplication(2, 2)); +//} + +// to do: test all error code output from project +TEST_F(ProjectTest, Run_error_code_test_NOT_CORRECT_COUNT_OF_OPERATION) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("+ +")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::NOT_CORRECT_COUNT_OF_OPERATION), + project_.get_error_code()); +} + +TEST_F(ProjectTest, Run_error_code_test_STACK_EMPTY) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::STACK_EMPTY), + project_.get_error_code()); +} + +TEST_F(ProjectTest, Run_error_code_test_STACK_NOT_CORRECT_EXPRESSION) { + ASSERT_EQ(polish_notation_constant::ERROR_VALUE, project_.run("2 3 &")); + ASSERT_EQ(static_cast(polish_notation_constant::error_code::NOT_CORRECT_EXPRESSION), + project_.get_error_code()); +} + +} // namespace testing +} // namespace dev