Multiple implementations of the same back-end application. The aim is to provide quick, side-by-side comparisons of different technologies (languages, frameworks, libraries) while preserving consistent business logic across all implementations.
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.
 
 
 
 
 
 

352 lines
9.0 KiB

package unit
import (
"context"
"errors"
"testing"
"time"
"autostore/internal/application/commands"
"autostore/internal/domain/entities"
"autostore/internal/domain/specifications"
)
func createTestCommand() (*commands.AddItemCommand, *mockItemRepository, *mockOrderService, *mockTimeProvider, *mockLogger) {
itemRepo := &mockItemRepository{}
orderService := &mockOrderService{}
timeProvider := &mockTimeProvider{
nowFunc: func() time.Time {
t, _ := time.Parse(dateFormat, mockedNow)
return t
},
}
expirationSpec := specifications.NewItemExpirationSpec()
logger := &mockLogger{}
cmd := commands.NewAddItemCommand(itemRepo, orderService, timeProvider, expirationSpec, logger)
return cmd, itemRepo, orderService, timeProvider, logger
}
func TestWhenItemNotExpiredThenItemSaved(t *testing.T) {
// Given
cmd, itemRepo, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
itemSaved := false
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
itemSaved = true
if item.GetName() != itemName {
t.Errorf("Expected item name %s, got %s", itemName, item.GetName())
}
if item.GetOrderURL() != orderURL {
t.Errorf("Expected order URL %s, got %s", orderURL, item.GetOrderURL())
}
if item.GetUserID().String() != userID {
t.Errorf("Expected user ID %s, got %s", userID, item.GetUserID().String())
}
return nil
}
// When
resultID, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID")
}
if !itemSaved {
t.Error("Expected item to be saved")
}
}
func TestWhenItemNotExpiredThenOrderIsNotPlaced(t *testing.T) {
// Given
cmd, _, orderService, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
orderPlaced := false
orderService.orderItemFunc = func(ctx context.Context, item *entities.ItemEntity) error {
orderPlaced = true
return nil
}
// When
_, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if orderPlaced {
t.Error("Expected order not to be placed for non-expired item")
}
}
func TestWhenItemNotExpiredThenNewItemIdIsReturned(t *testing.T) {
// Given
cmd, _, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
// When
resultID, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID")
}
}
func TestWhenItemIsExpiredThenOrderPlaced(t *testing.T) {
// Given
cmd, itemRepo, orderService, timeProvider, _ := createTestCommand()
// Set expiration time to 1 hour before current time to ensure it's expired
currentTime := timeProvider.Now()
expirationTime := currentTime.Add(-1 * time.Hour)
orderPlaced := false
var orderedItem *entities.ItemEntity
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return nil
}
orderService.orderItemFunc = func(ctx context.Context, item *entities.ItemEntity) error {
orderPlaced = true
orderedItem = item
return nil
}
// When
resultID, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID")
}
if !orderPlaced {
t.Error("Expected order to be placed for expired item")
}
if orderedItem == nil {
t.Error("Expected ordered item to be captured")
}
if orderedItem != nil && orderedItem.GetName() != itemName {
t.Errorf("Expected ordered item name %s, got %s", itemName, orderedItem.GetName())
}
}
func TestWhenItemNameIsEmptyThenErrorReturned(t *testing.T) {
// Given
cmd, _, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
// When
_, err := cmd.Execute(context.Background(), "", expirationTime, orderURL, userID)
// Then
if err == nil {
t.Error("Expected error for empty item name")
}
}
func TestWhenOrderUrlIsEmptyThenErrorReturned(t *testing.T) {
// Given
cmd, _, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
// When
_, err := cmd.Execute(context.Background(), itemName, expirationTime, "", userID)
// Then
if err == nil {
t.Error("Expected error for empty order URL")
}
}
func TestWhenUserIdIsEmptyThenErrorReturned(t *testing.T) {
// Given
cmd, _, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
// When
_, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, "")
// Then
if err == nil {
t.Error("Expected error for empty user ID")
}
}
func TestWhenOrderServiceFailsThenErrorLogged(t *testing.T) {
// Given
cmd, itemRepo, orderService, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, expiredDate)
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return nil
}
orderService.orderItemFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return errors.New("order service failed")
}
// When - the handler should not throw an exception when the order service fails
// It should log the error and continue
resultID, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error when order service fails, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID even when order service fails")
}
}
func TestWhenRepositorySaveThrowsExceptionThenErrorReturned(t *testing.T) {
// Given
cmd, itemRepo, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
expectedError := errors.New("repository error")
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return expectedError
}
// When
_, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err == nil {
t.Error("Expected error when repository save fails")
}
}
func TestWhenRepositorySaveThrowsExceptionThenOrderIsNotPlaced(t *testing.T) {
// Given
cmd, itemRepo, orderService, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, expiredDate)
expectedError := errors.New("repository error")
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return expectedError
}
orderPlaced := false
orderService.orderItemFunc = func(ctx context.Context, item *entities.ItemEntity) error {
orderPlaced = true
return nil
}
// When
_, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err == nil {
t.Error("Expected error when repository save fails")
}
if orderPlaced {
t.Error("Expected order not to be placed when repository save fails")
}
}
func TestWhenTimeProviderThrowsExceptionThenErrorReturned(t *testing.T) {
// Given
cmd, _, _, timeProvider, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
expectedError := errors.New("time provider error")
timeProvider.nowFunc = func() time.Time {
panic(expectedError)
}
// When
defer func() {
if r := recover(); r != nil {
// Expected panic
} else {
t.Error("Expected panic when time provider fails")
}
}()
cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
}
func TestWhenItemExpirationDateIsExactlyCurrentTimeThenOrderIsPlaced(t *testing.T) {
// Given
cmd, itemRepo, orderService, timeProvider, _ := createTestCommand()
// Use the exact current time from the time provider
currentTime := timeProvider.Now()
orderPlaced := false
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
return nil
}
orderService.orderItemFunc = func(ctx context.Context, item *entities.ItemEntity) error {
orderPlaced = true
return nil
}
// When
resultID, err := cmd.Execute(context.Background(), itemName, currentTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID")
}
if !orderPlaced {
t.Error("Expected order to be placed when expiration date equals current time")
}
}
func TestWhenItemExpirationDateIsInFutureThenItemSaved(t *testing.T) {
// Given
cmd, itemRepo, _, _, _ := createTestCommand()
expirationTime, _ := time.Parse(dateFormat, notExpiredDate)
itemSaved := false
itemRepo.saveFunc = func(ctx context.Context, item *entities.ItemEntity) error {
itemSaved = true
return nil
}
// When
resultID, err := cmd.Execute(context.Background(), itemName, expirationTime, orderURL, userID)
// Then
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if resultID == "" {
t.Error("Expected non-empty result ID")
}
if !itemSaved {
t.Error("Expected item to be saved when expiration date is in future")
}
}