You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
6.7 KiB
223 lines
6.7 KiB
#include "application/commands/AddItem.h" |
|
#include "domain/entities/Item.h" |
|
#include "mocks/MockItemRepository.h" |
|
#include "mocks/MockTimeProvider.h" |
|
#include "mocks/MockOrderService.h" |
|
#include "helpers/AddItemTestHelpers.h" |
|
#include <catch2/catch_test_macros.hpp> |
|
#include <catch2/matchers/catch_matchers_string.hpp> |
|
#include <trompeloeil.hpp> |
|
#include <memory> |
|
#include <stdexcept> |
|
|
|
using trompeloeil::_; |
|
|
|
using namespace nxl::autostore; |
|
using namespace std::chrono; |
|
|
|
TEST_CASE("AddItem Unit Tests", "[unit][AddItem]") |
|
{ |
|
test::MockItemRepository mockRepository; |
|
test::MockTimeProvider mockClock; |
|
test::MockOrderService mockOrderService; |
|
|
|
SECTION( |
|
"when user id is present and item is not expired then the item is saved") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
auto expectedItemId = "saved_item_id"; |
|
|
|
REQUIRE_CALL(mockRepository, save(testItem)).RETURN(expectedItemId); |
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
auto resultItemId = addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
REQUIRE(resultItemId == expectedItemId); |
|
} |
|
|
|
SECTION("when item has null user id then a runtime error is thrown") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
testItem.userId = domain::User::NULL_ID; |
|
|
|
FORBID_CALL(mockRepository, save(_)); |
|
FORBID_CALL(mockClock, now()); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When & Then |
|
REQUIRE_THROWS_AS(addItem.execute(std::move(testItem)), std::runtime_error); |
|
} |
|
|
|
SECTION("when item is expired then the order is placed") |
|
{ |
|
// Given |
|
auto testItem = test::createExpiredTestItem(); |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockOrderService, orderItem(_)); |
|
FORBID_CALL(mockRepository, save(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
// Order was placed (verified by REQUIRE_CALL above) |
|
} |
|
|
|
SECTION("when item is expired then null id is returned") |
|
{ |
|
// Given |
|
auto testItem = test::createExpiredTestItem(); |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockOrderService, orderItem(_)); |
|
FORBID_CALL(mockRepository, save(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
auto resultItemId = addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
REQUIRE(resultItemId == domain::Item::NULL_ID); |
|
} |
|
|
|
SECTION("when item expiration date is exactly current time then the order is " |
|
"placed") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
testItem.expirationDate = test::TEST_TIMEPOINT_NOW; |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockOrderService, orderItem(_)); |
|
FORBID_CALL(mockRepository, save(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
// Order was placed (verified by REQUIRE_CALL above) |
|
} |
|
|
|
SECTION("when item expiration date is exactly current time then null id is " |
|
"returned") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
testItem.expirationDate = test::TEST_TIMEPOINT_NOW; |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockOrderService, orderItem(_)); |
|
FORBID_CALL(mockRepository, save(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
auto resultItemId = addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
REQUIRE(resultItemId == domain::Item::NULL_ID); |
|
} |
|
|
|
SECTION("when item expiration date is in the future then the item is saved") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
auto expectedItemId = "saved_item_id"; |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockRepository, save(testItem)).RETURN(expectedItemId); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
// Item was saved (verified by REQUIRE_CALL above) |
|
} |
|
|
|
SECTION( |
|
"when item expiration date is in the future then the item id is returned") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
auto expectedItemId = "saved_item_id"; |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockRepository, save(testItem)).RETURN(expectedItemId); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When |
|
auto resultItemId = addItem.execute(std::move(testItem)); |
|
|
|
// Then |
|
REQUIRE(resultItemId == expectedItemId); |
|
} |
|
|
|
SECTION( |
|
"when repository save throws exception then a runtime error is thrown") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
auto expectedException = std::runtime_error("Repository error"); |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockRepository, save(testItem)).THROW(expectedException); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When & Then |
|
REQUIRE_THROWS_AS(addItem.execute(std::move(testItem)), std::runtime_error); |
|
} |
|
|
|
SECTION("when order service throws exception then a runtime error is thrown") |
|
{ |
|
// Given |
|
auto testItem = test::createExpiredTestItem(); |
|
auto expectedException = std::runtime_error("Order service error"); |
|
|
|
REQUIRE_CALL(mockClock, now()).RETURN(test::TEST_TIMEPOINT_NOW); |
|
REQUIRE_CALL(mockOrderService, orderItem(_)).THROW(expectedException); |
|
FORBID_CALL(mockRepository, save(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When & Then |
|
REQUIRE_THROWS_AS(addItem.execute(std::move(testItem)), std::runtime_error); |
|
} |
|
|
|
SECTION("when clock throws exception then a runtime error is thrown") |
|
{ |
|
// Given |
|
auto testItem = test::createTestItem(); |
|
auto expectedException = std::runtime_error("Clock error"); |
|
|
|
REQUIRE_CALL(mockClock, now()).THROW(expectedException); |
|
FORBID_CALL(mockRepository, save(_)); |
|
FORBID_CALL(mockOrderService, orderItem(_)); |
|
|
|
application::AddItem addItem(mockRepository, mockClock, mockOrderService); |
|
|
|
// When & Then |
|
REQUIRE_THROWS_AS(addItem.execute(std::move(testItem)), std::runtime_error); |
|
} |
|
} |