Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mkorniichuk #7

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ project(dummy_cmake_project)
set(CMAKE_CXX_STANDARD 14)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

set(SOURCES project.cc)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc)

add_library(ProjectLib ${SOURCES})

add_executable(project main.cc)
Expand Down
11 changes: 11 additions & 0 deletions include/fixed_queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <queue>

namespace dev {
class FixedSizeQueue : public std::queue<float> {
public:
void push(const float& item);
bool getFirst(float& item);
private:
static constexpr int _size = 2;
};
}
10 changes: 10 additions & 0 deletions include/iproject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once
#include "string"

namespace dev{

class IProject {
virtual float run(const std::string& expression) = 0;
};

}
19 changes: 19 additions & 0 deletions include/project.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once
#include "iproject.h"
#include "fixed_queue.h"

#include <vector>
#include <string>
#include <sstream>

namespace dev {

class Project : public IProject {
// IProject interface
public:
float run(const std::string& expression = "");

private:
FixedSizeQueue _queue;
};
} // namespace dev
19 changes: 19 additions & 0 deletions include/string_generator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace dev {
class StringGenerator{
public:
StringGenerator(const std::string& basic);
bool next(std::string& result);
bool empty();

static bool isOperation(const std::string& item);
static bool isOperand(const std::string& item);
static bool getOperand(const std::string& item, float& result);

static constexpr char cPlus = '+';
static constexpr char cMinus = '-';
static constexpr char cMult = '*';
static constexpr char cDiv = '/';
private:
std::string _basic;
};
}
9 changes: 0 additions & 9 deletions iproject.h

This file was deleted.

19 changes: 17 additions & 2 deletions main.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
#include "project.h"
#include <iostream>

int main() {
return 0;
int main(int argc, char *argv[]) {
//TODO:
// There should be easier way to convert CL args to a single string
std::string args= "";
for (int i = 1; i < argc; ++i) {
args += argv[i];
if (i != argc-1) {
args += ' ';
}
}

dev::Project project;
float result = project.run(args);
std::cout << "Result: " << result << std::endl;

return 0;
}
8 changes: 0 additions & 8 deletions project.cc

This file was deleted.

11 changes: 0 additions & 11 deletions project.h

This file was deleted.

21 changes: 21 additions & 0 deletions src/fixed_queue.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "fixed_queue.h"

namespace dev {
void FixedSizeQueue::push(const float& item){
while (_size <= this->size()){
this->pop();
}
std::queue<float>::push(item);
}

// Not obvious naming
bool FixedSizeQueue::getFirst(float& result) {
result = 0; // result will be changed it bad case (if stack is empty)
if (this->empty()){
return false;
}
result = this->front();
this->pop();
return true;
}
}
64 changes: 64 additions & 0 deletions src/project.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "project.h"
#include "string_generator.h"

namespace dev {

float Project::run(const std::string& expression) {
auto stuff = [this](const std::string& operation, float& result) {
float operand1;
float operand2;

if (!_queue.getFirst(operand1) || //getFirst change stack. but name of function does not say about it
! _queue.getFirst(operand2)) {
// UNDEFINED!!!
throw std::runtime_error("Single operand! Undefined behaviour!");
}

const char& cOperation = operation.front();
switch (cOperation) {
case StringGenerator::cPlus:
result = operand1 + operand2;
break;
case StringGenerator::cMinus:
result = operand1 - operand2;
break;
case StringGenerator::cMult:
result = operand1 * operand2;
break;
case StringGenerator::cDiv:
result = operand1 / operand2; // I can write 1 / 0
break;
default:
// UNREACHABLE!!!
throw std::runtime_error("Undefined operation!");
}
return true;
};

auto sGenerator = StringGenerator(expression);

// Think of case, when this result will be returned in case of wrong line
float result = 0;
std::string item;
while(sGenerator.next(item)) {
// Not obvious loop
if (StringGenerator::isOperation(item)) {
stuff(item, result);
_queue.push(result);
continue;
}

if (StringGenerator::getOperand(item, result)) {
_queue.push(result);
continue;
}

// UNREACHABLE!!!"
throw std::runtime_error("Unreachable!");
}


_queue.getFirst(result);
return result;
}
} // namespace dev
66 changes: 66 additions & 0 deletions src/string_generator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <vector>
#include <sstream>
#include "string_generator.h"

namespace dev {
StringGenerator::StringGenerator(const std::string& basic)
: _basic(basic) {}

bool StringGenerator::empty() {
return _basic.empty();
}

bool StringGenerator::next(std::string& result) {
result = "";
//not obvious loop!
while(!empty()) {

// get front and pop!!!
auto item = _basic.front();
_basic.erase(0,1);

// how about const?
if (' ' == item) {
break;
}
result += item;
}
return !result.empty();
}

bool StringGenerator::isOperation(const std::string& item) {
if (item.length() > 1) {
return false;
}

const auto& front = item.front();

switch (front) {
case StringGenerator::cPlus:
case StringGenerator::cMinus:
case StringGenerator::cDiv:
case StringGenerator::cMult:
return true;
default:
return false;
}
}

bool StringGenerator::isOperand(const std::string& item) {
float result;
return getOperand(item, result);
}

bool StringGenerator::getOperand(const std::string& item, float& result) {
if (item.empty()) {
return false;
}

// TODO:
// I bet this part could be simplified...
std::istringstream iss(item);
iss >> std::noskipws >> result; // noskipws considers leading whitespace invalid
// Check the entire string was consumed and if either failbit or badbit is set
return iss.eof() && !iss.fail();
}
}
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@ include_directories (${CMAKE_SOURCE_DIR})
include(AddGoogleTest)

add_executable (ProjectTest project_test.cc)
add_executable (FixedQueueTest fixed_size_queue_test.cc)

add_gtest(ProjectTest)
add_gtest(FixedQueueTest)

target_link_libraries(ProjectTest PUBLIC ProjectLib)
target_link_libraries(FixedQueueTest PUBLIC ProjectLib)
52 changes: 52 additions & 0 deletions test/fixed_size_queue_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

#include "fixed_queue.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>

namespace dev {
namespace testing {

class FixedSizeQueueTest : public ::testing::Test {
public:
void SetUp() override {
FixedSizeQueue tmp_queue;
std::swap(queue_, tmp_queue);
}
void TearDown() override {}

FixedSizeQueue queue_;
};

TEST_F(FixedSizeQueueTest, Push) {
float item = 5.1;
EXPECT_NO_THROW(queue_.push(item));
}

TEST_F(FixedSizeQueueTest, GetFirst) {
float item_1 = 5.1;
float item_2 = 3.2;
queue_.push(item_1);
queue_.push(item_2);

float result = 0;
ASSERT_TRUE(queue_.getFirst(result));

EXPECT_EQ(result, item_1);
}

TEST_F(FixedSizeQueueTest, PushThreeItems) {
float item_1 = 5.1;
float item_2 = 3.2;
float item_3 = 1.1;
queue_.push(item_1);
queue_.push(item_2);
queue_.push(item_3);

float result = 0;
ASSERT_TRUE(queue_.getFirst(result));

EXPECT_EQ(result, item_2);
}

} // namespace testing
} // namespace dev
33 changes: 32 additions & 1 deletion test/project_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,40 @@ class ProjectTest : public ::testing::Test {
dev::Project project_;
};

TEST_F(ProjectTest, Run) {
TEST_F(ProjectTest, Run_Basic) {
ASSERT_EQ(0, project_.run());
ASSERT_EQ(10, project_.run("10"));
ASSERT_EQ(10, project_.run("10 4"));
}

TEST_F(ProjectTest, Simple_Operations) {
ASSERT_EQ(15, project_.run("10 5 +"));
ASSERT_EQ(5, project_.run("10 5 -"));
ASSERT_EQ(50, project_.run("10 5 *"));
ASSERT_EQ(2, project_.run("10 5 /"));
}

TEST_F(ProjectTest, Simple_Operations_Float) {
ASSERT_NEAR(15.2, project_.run("10.1 5.1 +"), 0.01);
ASSERT_NEAR(5, project_.run("10.1 5.1 -"), 0.01);
ASSERT_NEAR(51.51, project_.run("10.1 5.1 *"), 0.01);
ASSERT_NEAR(2.02, project_.run("10.1 5 /"), 0.01);
}

TEST_F(ProjectTest, Simple_Operations_Exceptions) {
ASSERT_THROW(project_.run("a"), std::runtime_error);
ASSERT_THROW(project_.run("a a"), std::runtime_error);
ASSERT_THROW(project_.run("+"), std::runtime_error);
ASSERT_THROW(project_.run("10 +"), std::runtime_error);
}

TEST_F(ProjectTest, Simple_Operations_Complex) {
EXPECT_EQ(17, project_.run("10 5 + 2 +"));
EXPECT_EQ(7, project_.run("10 5 2 +"));
}

//TODO:
// Increase coverage

} // namespace testing
} // namespace dev