diff --git a/CMakeLists.txt b/CMakeLists.txt index 67e3f8e..1aaea1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,19 +2,36 @@ cmake_minimum_required(VERSION 3.2) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) +#set(CMAKE_CXX_COMPILER g++-10) project(Cars) +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG main +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) set(SRC_LIST + Car.cpp ElectricCar.cpp ElectricEngine.cpp HybridCar.cpp - main.cpp PetrolCar.cpp PetrolEngine.cpp Car.cpp ) -add_executable(${PROJECT_NAME} ${SRC_LIST}) -target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Wpedantic -Wextra) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}) +add_executable(${PROJECT_NAME} ${SRC_LIST} main.cpp) + +#target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Wpedantic -Wextra) +#target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}) + +add_executable(${PROJECT_NAME}-ut ${SRC_LIST} test.cpp) +target_link_libraries(${PROJECT_NAME}-ut gtest_main) + +enable_testing() +add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}) diff --git a/Car.cpp b/Car.cpp index 945e888..64ce3aa 100644 --- a/Car.cpp +++ b/Car.cpp @@ -3,5 +3,22 @@ void Car::turnLeft() { std::cout << __FUNCTION__ << std::endl; } void Car::turnRight() { std::cout << __FUNCTION__ << std::endl; } -void Car::brake() { std::cout << __FUNCTION__ << std::endl; } -void Car::accelerate(int) { std::cout << __FUNCTION__ << std::endl; } + +void Car::brake() { + speed_ = 0.0; +} +void Car::accelerate(int speed) { + if(speed < 0.0) { + throw std::range_error("Speed can't be below zero!"); + } + if(speed > maxSpeed) { + throw std::range_error("Speed can't be over 300.0 km/h!"); + } + speed_ = speed; +} +void Car::changeEngine(std::unique_ptr) { + throw std::invalid_argument("This is not a petrol car!"); +} +void Car::changeEngine(std::unique_ptr) { + throw std::invalid_argument("This is not an electric car!"); +} diff --git a/Car.hpp b/Car.hpp index 4c8fd42..d25e051 100644 --- a/Car.hpp +++ b/Car.hpp @@ -1,12 +1,33 @@ #pragma once +#include +#include +#include "ElectricEngine.hpp" +#include "PetrolEngine.hpp" + +constexpr float maxSpeed = 300.0; class Car { public: + virtual ~Car(){} + void turnLeft(); void turnRight(); void brake(); void accelerate(int speed); virtual void refill() = 0; - virtual ~Car(){} + virtual void changeEngine(std::unique_ptr enginePtr); + virtual void changeEngine(std::unique_ptr enginePtr); + + // getters + float getSpeed() const { return speed_; } + + // execption + class CarMoving : public std::logic_error { + public: + CarMoving(const std::string &msg) : + std::logic_error(msg) {} + }; +private: + float speed_; }; diff --git a/ElectricCar.cpp b/ElectricCar.cpp index 0739201..51647ca 100644 --- a/ElectricCar.cpp +++ b/ElectricCar.cpp @@ -1,17 +1,20 @@ #include "ElectricCar.hpp" #include -ElectricCar::ElectricCar(ElectricEngine* engine) - : engine_(engine) +ElectricCar::ElectricCar(std::unique_ptr engine) + : engine_(std::move(engine)) { std::cout << __FUNCTION__ << std::endl; } ElectricCar::~ElectricCar() { std::cout << __FUNCTION__ << std::endl; } void ElectricCar::charge() { std::cout << __FUNCTION__ << std::endl; } -void ElectricCar::changeEngine(ElectricEngine* ee) { - delete engine_; - engine_ = ee; +void ElectricCar::changeEngine(std::unique_ptr electricEngine) { + if(this->getSpeed() != 0.0) { + engine_ = std::move(electricEngine); + return; + } + throw Car::CarMoving{"Can't change an engine when car is moving!"}; } void ElectricCar::refill() { charge(); diff --git a/ElectricCar.hpp b/ElectricCar.hpp index e57fd3d..c7d0692 100644 --- a/ElectricCar.hpp +++ b/ElectricCar.hpp @@ -5,13 +5,13 @@ class ElectricCar : public virtual Car { public: - ElectricCar(ElectricEngine* engine); + ElectricCar(std::unique_ptr engine); ~ElectricCar(); - void changeEngine(ElectricEngine* ee); + void changeEngine(std::unique_ptr electricEngine); void refill() override; private: void charge(); - ElectricEngine* engine_; + std::unique_ptr engine_; }; diff --git a/HybridCar.cpp b/HybridCar.cpp index bcb0e09..c061786 100644 --- a/HybridCar.cpp +++ b/HybridCar.cpp @@ -1,9 +1,9 @@ #include "HybridCar.hpp" #include -HybridCar::HybridCar(PetrolEngine* petrolEng, ElectricEngine* electricEng) - : ElectricCar(electricEng) - , PetrolCar(petrolEng) +HybridCar::HybridCar(std::unique_ptr petrolEng, std::unique_ptr electricEng) + : ElectricCar(std::move(electricEng)) + , PetrolCar(std::move(petrolEng)) { std::cout << __FUNCTION__ << std::endl; } @@ -12,4 +12,5 @@ HybridCar::~HybridCar() { std::cout << __FUNCTION__ << std::endl; } void HybridCar::refill() { ElectricCar::refill(); PetrolCar::refill(); -} \ No newline at end of file +} + diff --git a/HybridCar.hpp b/HybridCar.hpp index 18876cd..6d1ded6 100644 --- a/HybridCar.hpp +++ b/HybridCar.hpp @@ -8,7 +8,7 @@ class HybridCar : public ElectricCar, public PetrolCar { public: - HybridCar(PetrolEngine* petrolEng, ElectricEngine* electricEng); + HybridCar(std::unique_ptr petrolEng, std::unique_ptr electricEng); ~HybridCar(); void refill() override; }; diff --git a/InvalidGear.hpp b/InvalidGear.hpp new file mode 100644 index 0000000..d4b8920 --- /dev/null +++ b/InvalidGear.hpp @@ -0,0 +1,6 @@ +#pragma once +#include + +struct InvalidGear : public std::logic_error { + InvalidGear(std::string msg) : std::logic_error(msg) {} +}; \ No newline at end of file diff --git a/PetrolCar.cpp b/PetrolCar.cpp index 12ddc07..1d04b39 100644 --- a/PetrolCar.cpp +++ b/PetrolCar.cpp @@ -1,18 +1,26 @@ #include "PetrolCar.hpp" #include -PetrolCar::PetrolCar(PetrolEngine* engine) - : engine_(engine) +PetrolCar::PetrolCar(std::unique_ptr engine) + : engine_(std::move(engine)) { std::cout << __FUNCTION__ << std::endl; } PetrolCar::~PetrolCar() { std::cout << __FUNCTION__ << std::endl; } void PetrolCar::refuel() { std::cout << __FUNCTION__ << std::endl; } -void PetrolCar::changeEngine(PetrolEngine* pe) { - delete engine_; - engine_ = pe; + +void PetrolCar::changeGear(int gear) { + engine_->changeGear(gear); +} +void PetrolCar::changeEngine(std::unique_ptr petrolEngine) { + if(this->getSpeed() != 0.0) { + engine_ = std::move(petrolEngine); + return; + } + throw Car::CarMoving{"Can't change an engine when car is moving!"}; } + void PetrolCar::refill() { refuel(); } diff --git a/PetrolCar.hpp b/PetrolCar.hpp index f03c382..37566bf 100644 --- a/PetrolCar.hpp +++ b/PetrolCar.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #include "PetrolEngine.hpp" #include "Car.hpp" @@ -6,13 +8,14 @@ class PetrolCar : virtual public Car { public: - PetrolCar(PetrolEngine* engine); + PetrolCar(std::unique_ptr petrolEngine); ~PetrolCar(); - void changeEngine(PetrolEngine* pe); + void changeGear(int gear); + void changeEngine(std::unique_ptr petrolEngine); void refill() override; private: void refuel(); - PetrolEngine* engine_; + std::unique_ptr engine_; }; diff --git a/PetrolEngine.cpp b/PetrolEngine.cpp index 2aeceb9..863344e 100644 --- a/PetrolEngine.cpp +++ b/PetrolEngine.cpp @@ -1,5 +1,7 @@ #include "PetrolEngine.hpp" #include +#include + PetrolEngine::PetrolEngine(int power, float capacity, int gears) : power_(power) @@ -15,6 +17,13 @@ void PetrolEngine::changeGear(int gear) // TODO: Add checking if gear is between -1 and gears_ // -1 is for REAR // 0 is for NEUTRAL + if(gear < -1 || gear > gears_) { + throw InvalidGear("Invalid gear. Gear needs to be between 1 and " + std::to_string(gear)); + } + if(gear != 0 && abs(gear - currentGear_) != 1) { + throw InvalidGear("Invalid gear change from: " + std::to_string(currentGear_)+ " to: " + std::to_string(gear)); + } currentGear_ = gear; + std::cout << __FUNCTION__ << std::endl; } diff --git a/PetrolEngine.hpp b/PetrolEngine.hpp index 0996576..83a4747 100644 --- a/PetrolEngine.hpp +++ b/PetrolEngine.hpp @@ -1,8 +1,10 @@ #pragma once +#include "InvalidGear.hpp" class PetrolEngine { public: + PetrolEngine(int power, float capacity, int gears); void changeGear(int gear); diff --git a/main.cpp b/main.cpp index 400296a..3fbecd7 100644 --- a/main.cpp +++ b/main.cpp @@ -6,29 +6,24 @@ int main() { + // std::cout << std::endl << "OPEL" << std::endl; + // PetrolCar opel(new PetrolEngine(120, 1800, 6)); + // opel.accelerate(50); + // opel.brake(); + // opel.accelerate(-900); + // opel.refuel(); - std::cout << std::endl << "OPEL" << std::endl; - PetrolCar opel(new PetrolEngine(120, 1800, 6)); - Car* car = &opel; - car->accelerate(50); - car->brake(); - car->accelerate(-900); - car->refill(); - // car->changeEngine(new PetrolEngine(150, 700, 7)); - - std::cout << std::endl << "NISSAN" << std::endl; - ElectricCar nissan(new ElectricEngine(130, 650)); - car = &nissan; - car->refill(); - car->accelerate(80); + // std::cout << std::endl << "NISSAN" << std::endl; + // ElectricCar nissan(new ElectricEngine(130, 650)); + // nissan.charge(); + // nissan.accelerate(80); // nissan.engine_ = new ElectricEngine(150, 700); // Changing an engine during driving is not safe - // car->changeEngine(new ElectricEngine(150, 700)); - car->turnLeft(); + // nissan.turnLeft(); - std::cout << std::endl << "TOYOTA" << std::endl; - HybridCar toyota(new PetrolEngine(80, 1400, 5), new ElectricEngine(100, 540)); - car = &toyota; - car->accelerate(100); - car->brake(); - car->refill(); + // std::cout << std::endl << "TOYOTA" << std::endl; + // HybridCar toyota(new PetrolEngine(80, 1400, 5), new ElectricEngine(100, 540)); + // toyota.accelerate(100); + // toyota.brake(); + // toyota.charge(); + // toyota.refuel(); } diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..9698951 --- /dev/null +++ b/test.cpp @@ -0,0 +1,52 @@ +#include "gtest/gtest.h" +#include "Car.hpp" +#include "PetrolCar.hpp" +#include "ElectricCar.hpp" +#include "HybridCar.hpp" +#include "InvalidGear.hpp"" + + +// Tests throwing std::range_error when accelerate to speed = -999 or speed > maxSpeed is invoked +TEST(PetrolCarClassTest, ShouldThrowRangeError) { + PetrolCar opel(std::make_unique(120, 1800, 6)); + EXPECT_THROW(opel.accelerate(-999), std::range_error); + EXPECT_THROW(opel.accelerate(350), std::range_error); + +} +// Tests throwing InvalidGear when wrong gear is set +TEST(PetrolCarChangeGearTest, ShouldThrowIvalidGear) { + PetrolCar opel(std::make_unique(120, 1800, 6)); + EXPECT_THROW(opel.changeGear(-2), InvalidGear); + EXPECT_THROW(opel.changeGear(7), InvalidGear); + EXPECT_THROW(opel.changeGear(2), InvalidGear); + opel.changeGear(1); + EXPECT_THROW(opel.changeGear(5), InvalidGear); +} +// Tests if changeGear doesn't throw an exception +TEST(PetrolCarChangeGearTest, ShouldNotThrowException) { + PetrolCar opel(std::make_unique(120, 1800, 6)); + EXPECT_NO_THROW(opel.changeGear(1)); + EXPECT_NO_THROW(opel.changeGear(2)); + EXPECT_NO_THROW(opel.changeGear(3)); + EXPECT_NO_THROW(opel.changeGear(2)); + EXPECT_NO_THROW(opel.changeGear(1)); + EXPECT_NO_THROW(opel.changeGear(0)); + EXPECT_NO_THROW(opel.changeGear(-1)); +} +// Tests throwing std::range_error when accelerate to speed = -999 or speed > maxSpeed is invoked +TEST(ElectricCarClassTest, ShouldThrowRangeError) { + ElectricCar nissan(std::make_unique(130, 650)); + EXPECT_THROW(nissan.accelerate(-999), std::range_error); + EXPECT_THROW(nissan.accelerate(350), std::range_error); +} +// Tests throwing std::invalid_argument when changing engine for the wrong one +TEST(CarClassPointerTest, ShouldThrowInvalidArgument) { + ElectricCar nissan(std::make_unique(130, 650)); + Car * car = &nissan; + // Electric car can't have petrol engine + EXPECT_THROW(car->changeEngine(std::make_unique(150, 700, 7)), std::invalid_argument); + PetrolCar opel(std::make_unique(120, 1800, 6)); + car = &opel; + // Petrol car can't have electric engine + EXPECT_THROW(car->changeEngine(std::make_unique(130, 650)), std::invalid_argument); +} \ No newline at end of file