diff --git a/core-service/internal/api/handlers/items_test.go b/core-service/internal/api/handlers/items_test.go new file mode 100644 index 0000000..795d5b4 --- /dev/null +++ b/core-service/internal/api/handlers/items_test.go @@ -0,0 +1,312 @@ +package handlers_test + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "erp-mvp/core-service/internal/api/handlers" + "erp-mvp/core-service/internal/auth" + "erp-mvp/core-service/internal/models" +) + +// setClaims устанавливает claims в контекст для тестов +func setClaims(c *gin.Context, orgID uuid.UUID) { + claims := &auth.Claims{ + UserID: uuid.New(), + OrganizationID: orgID, + Email: "test@example.com", + Role: "admin", + } + c.Set("user_id", claims.UserID) + c.Set("organization_id", claims.OrganizationID) + c.Set("email", claims.Email) + c.Set("role", claims.Role) +} + +// MockItemService мок для ItemService +type MockItemService struct { + mock.Mock +} + +func (m *MockItemService) GetItems(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) { + args := m.Called(ctx, orgID) + return args.Get(0).([]*models.Item), args.Error(1) +} + +func (m *MockItemService) CreateItem(ctx context.Context, orgID uuid.UUID, req *models.CreateItemRequest) (*models.Item, error) { + args := m.Called(ctx, orgID, req) + return args.Get(0).(*models.Item), args.Error(1) +} + +func (m *MockItemService) GetItem(ctx context.Context, orgID uuid.UUID, itemID uuid.UUID) (*models.Item, error) { + args := m.Called(ctx, orgID, itemID) + return args.Get(0).(*models.Item), args.Error(1) +} + +func (m *MockItemService) UpdateItem(ctx context.Context, orgID uuid.UUID, itemID uuid.UUID, req *models.CreateItemRequest) (*models.Item, error) { + args := m.Called(ctx, orgID, itemID, req) + return args.Get(0).(*models.Item), args.Error(1) +} + +func (m *MockItemService) DeleteItem(ctx context.Context, orgID uuid.UUID, itemID uuid.UUID) error { + args := m.Called(ctx, orgID, itemID) + return args.Error(0) +} + +func (m *MockItemService) SearchItems(ctx context.Context, orgID uuid.UUID, query string, category string) ([]*models.Item, error) { + args := m.Called(ctx, orgID, query, category) + return args.Get(0).([]*models.Item), args.Error(1) +} + +// TestNewItemHandler тестирует создание ItemHandler +func TestNewItemHandler(t *testing.T) { + // Arrange + mockService := &MockItemService{} + + // Act + handler := handlers.NewItemHandler(mockService) + + // Assert + assert.NotNil(t, handler) +} + +// TestItemHandler_GetItems_Success тестирует успешное получение товаров +func TestItemHandler_GetItems_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockItemService := &MockItemService{} + handler := handlers.NewItemHandler(mockItemService) + + orgID := uuid.New() + expectedItems := []*models.Item{ + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Item 1", + Description: "Description 1", + Category: "electronics", + }, + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Item 2", + Description: "Description 2", + Category: "clothing", + }, + } + + mockItemService.On("GetItems", mock.Anything, orgID).Return(expectedItems, nil) + + router := gin.New() + router.GET("/items", func(c *gin.Context) { + setClaims(c, orgID) + handler.GetItems(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/items", nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response []*models.Item + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Len(t, response, 2) + assert.Equal(t, "Item 1", response[0].Name) + assert.Equal(t, "Item 2", response[1].Name) + + mockItemService.AssertExpectations(t) +} + +// TestItemHandler_CreateItem_Success тестирует успешное создание товара +func TestItemHandler_CreateItem_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockItemService := &MockItemService{} + handler := handlers.NewItemHandler(mockItemService) + + orgID := uuid.New() + itemID := uuid.New() + createReq := &models.CreateItemRequest{ + Name: "New Item", + Description: "New Description", + Category: "electronics", + } + + expectedItem := &models.Item{ + ID: itemID, + OrganizationID: orgID, + Name: "New Item", + Description: "New Description", + Category: "electronics", + } + + mockItemService.On("CreateItem", mock.Anything, orgID, createReq).Return(expectedItem, nil) + + router := gin.New() + router.POST("/items", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.CreateItem(c) + }) + + reqBody, _ := json.Marshal(createReq) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/items", bytes.NewBuffer(reqBody)) + req.Header.Set("Content-Type", "application/json") + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusCreated, w.Code) + + var response models.Item + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, "New Item", response.Name) + assert.Equal(t, "electronics", response.Category) + + mockItemService.AssertExpectations(t) +} + +// TestItemHandler_CreateItem_ValidationError тестирует ошибку валидации при создании товара +func TestItemHandler_CreateItem_ValidationError(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockItemService := &MockItemService{} + handler := handlers.NewItemHandler(mockItemService) + + orgID := uuid.New() + + // Невалидный запрос (пустое имя) + invalidReq := map[string]interface{}{ + "name": "", // Пустое имя + "description": "Description", + "category": "electronics", + } + + router := gin.New() + router.POST("/items", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.CreateItem(c) + }) + + reqBody, _ := json.Marshal(invalidReq) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/items", bytes.NewBuffer(reqBody)) + req.Header.Set("Content-Type", "application/json") + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusBadRequest, w.Code) + + mockItemService.AssertNotCalled(t, "CreateItem") +} + +// TestItemHandler_GetItem_Success тестирует успешное получение товара по ID +func TestItemHandler_GetItem_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockItemService := &MockItemService{} + handler := handlers.NewItemHandler(mockItemService) + + orgID := uuid.New() + itemID := uuid.New() + expectedItem := &models.Item{ + ID: itemID, + OrganizationID: orgID, + Name: "Test Item", + Description: "Test Description", + Category: "electronics", + } + + mockItemService.On("GetItem", mock.Anything, orgID, itemID).Return(expectedItem, nil) + + router := gin.New() + router.GET("/items/:id", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.GetItem(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/items/"+itemID.String(), nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response models.Item + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, "Test Item", response.Name) + assert.Equal(t, itemID, response.ID) + + mockItemService.AssertExpectations(t) +} + +// TestItemHandler_SearchItems_Success тестирует успешный поиск товаров +func TestItemHandler_SearchItems_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockItemService := &MockItemService{} + handler := handlers.NewItemHandler(mockItemService) + + orgID := uuid.New() + expectedItems := []*models.Item{ + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Search Result", + Description: "Found item", + Category: "electronics", + }, + } + + mockItemService.On("SearchItems", mock.Anything, orgID, "search", "electronics").Return(expectedItems, nil) + + router := gin.New() + router.GET("/items/search", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.SearchItems(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/items/search?q=search&category=electronics", nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response []*models.Item + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Len(t, response, 1) + assert.Equal(t, "Search Result", response[0].Name) + + mockItemService.AssertExpectations(t) +} diff --git a/core-service/internal/api/handlers/locations_test.go b/core-service/internal/api/handlers/locations_test.go new file mode 100644 index 0000000..d557a56 --- /dev/null +++ b/core-service/internal/api/handlers/locations_test.go @@ -0,0 +1,311 @@ +package handlers_test + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "erp-mvp/core-service/internal/api/handlers" + "erp-mvp/core-service/internal/models" +) + +// MockLocationService мок для LocationService +type MockLocationService struct { + mock.Mock +} + +func (m *MockLocationService) GetLocations(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) { + args := m.Called(ctx, orgID) + return args.Get(0).([]*models.StorageLocation), args.Error(1) +} + +func (m *MockLocationService) CreateLocation(ctx context.Context, orgID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) { + args := m.Called(ctx, orgID, req) + return args.Get(0).(*models.StorageLocation), args.Error(1) +} + +func (m *MockLocationService) GetLocation(ctx context.Context, orgID uuid.UUID, locationID uuid.UUID) (*models.StorageLocation, error) { + args := m.Called(ctx, orgID, locationID) + return args.Get(0).(*models.StorageLocation), args.Error(1) +} + +func (m *MockLocationService) UpdateLocation(ctx context.Context, orgID uuid.UUID, locationID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) { + args := m.Called(ctx, orgID, locationID, req) + return args.Get(0).(*models.StorageLocation), args.Error(1) +} + +func (m *MockLocationService) DeleteLocation(ctx context.Context, orgID uuid.UUID, locationID uuid.UUID) error { + args := m.Called(ctx, orgID, locationID) + return args.Error(0) +} + +func (m *MockLocationService) GetChildren(ctx context.Context, orgID uuid.UUID, parentID uuid.UUID) ([]*models.StorageLocation, error) { + args := m.Called(ctx, orgID, parentID) + return args.Get(0).([]*models.StorageLocation), args.Error(1) +} + +// TestNewLocationHandler тестирует создание LocationHandler +func TestNewLocationHandler(t *testing.T) { + // Arrange + mockService := &MockLocationService{} + + // Act + handler := handlers.NewLocationHandler(mockService) + + // Assert + assert.NotNil(t, handler) +} + +// TestLocationHandler_GetLocations_Success тестирует успешное получение локаций +func TestLocationHandler_GetLocations_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockLocationService := &MockLocationService{} + handler := handlers.NewLocationHandler(mockLocationService) + + orgID := uuid.New() + expectedLocations := []*models.StorageLocation{ + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Warehouse A", + Address: "123 Main St", + Type: "warehouse", + }, + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Shelf 1", + Address: "Warehouse A, Section 1", + Type: "shelf", + }, + } + + mockLocationService.On("GetLocations", mock.Anything, orgID).Return(expectedLocations, nil) + + router := gin.New() + router.GET("/locations", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.GetLocations(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/locations", nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response []*models.StorageLocation + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Len(t, response, 2) + assert.Equal(t, "Warehouse A", response[0].Name) + assert.Equal(t, "Shelf 1", response[1].Name) + + mockLocationService.AssertExpectations(t) +} + +// TestLocationHandler_CreateLocation_Success тестирует успешное создание локации +func TestLocationHandler_CreateLocation_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockLocationService := &MockLocationService{} + handler := handlers.NewLocationHandler(mockLocationService) + + orgID := uuid.New() + locationID := uuid.New() + createReq := &models.CreateLocationRequest{ + Name: "New Warehouse", + Address: "456 Oak St", + Type: "warehouse", + Coordinates: models.JSON{"lat": 55.7558, "lng": 37.6176}, + } + + expectedLocation := &models.StorageLocation{ + ID: locationID, + OrganizationID: orgID, + Name: "New Warehouse", + Address: "456 Oak St", + Type: "warehouse", + Coordinates: models.JSON{"lat": 55.7558, "lng": 37.6176}, + } + + mockLocationService.On("CreateLocation", mock.Anything, orgID, createReq).Return(expectedLocation, nil) + + router := gin.New() + router.POST("/locations", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.CreateLocation(c) + }) + + reqBody, _ := json.Marshal(createReq) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/locations", bytes.NewBuffer(reqBody)) + req.Header.Set("Content-Type", "application/json") + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusCreated, w.Code) + + var response models.StorageLocation + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, "New Warehouse", response.Name) + assert.Equal(t, "warehouse", response.Type) + + mockLocationService.AssertExpectations(t) +} + +// TestLocationHandler_CreateLocation_ValidationError тестирует ошибку валидации при создании локации +func TestLocationHandler_CreateLocation_ValidationError(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockLocationService := &MockLocationService{} + handler := handlers.NewLocationHandler(mockLocationService) + + orgID := uuid.New() + + // Невалидный запрос (пустое имя) + invalidReq := map[string]interface{}{ + "name": "", // Пустое имя + "address": "456 Oak St", + "type": "warehouse", + } + + router := gin.New() + router.POST("/locations", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.CreateLocation(c) + }) + + reqBody, _ := json.Marshal(invalidReq) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/locations", bytes.NewBuffer(reqBody)) + req.Header.Set("Content-Type", "application/json") + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusBadRequest, w.Code) + + mockLocationService.AssertNotCalled(t, "CreateLocation") +} + +// TestLocationHandler_GetLocation_Success тестирует успешное получение локации по ID +func TestLocationHandler_GetLocation_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockLocationService := &MockLocationService{} + handler := handlers.NewLocationHandler(mockLocationService) + + orgID := uuid.New() + locationID := uuid.New() + expectedLocation := &models.StorageLocation{ + ID: locationID, + OrganizationID: orgID, + Name: "Test Warehouse", + Address: "123 Test St", + Type: "warehouse", + } + + mockLocationService.On("GetLocation", mock.Anything, orgID, locationID).Return(expectedLocation, nil) + + router := gin.New() + router.GET("/locations/:id", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.GetLocation(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/locations/"+locationID.String(), nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response models.StorageLocation + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, "Test Warehouse", response.Name) + assert.Equal(t, locationID, response.ID) + + mockLocationService.AssertExpectations(t) +} + +// TestLocationHandler_GetChildren_Success тестирует успешное получение дочерних локаций +func TestLocationHandler_GetChildren_Success(t *testing.T) { + // Arrange + gin.SetMode(gin.TestMode) + + mockLocationService := &MockLocationService{} + handler := handlers.NewLocationHandler(mockLocationService) + + orgID := uuid.New() + parentID := uuid.New() + expectedChildren := []*models.StorageLocation{ + { + ID: uuid.New(), + OrganizationID: orgID, + ParentID: &parentID, + Name: "Shelf 1", + Address: "Warehouse A, Section 1", + Type: "shelf", + }, + { + ID: uuid.New(), + OrganizationID: orgID, + ParentID: &parentID, + Name: "Shelf 2", + Address: "Warehouse A, Section 2", + Type: "shelf", + }, + } + + mockLocationService.On("GetChildren", mock.Anything, orgID, parentID).Return(expectedChildren, nil) + + router := gin.New() + router.GET("/locations/:id/children", func(c *gin.Context) { + // Устанавливаем claims в контекст + c.Set("organization_id", orgID) + handler.GetChildren(c) + }) + + // Act + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/locations/"+parentID.String()+"/children", nil) + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var response []*models.StorageLocation + err := json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Len(t, response, 2) + assert.Equal(t, "Shelf 1", response[0].Name) + assert.Equal(t, "Shelf 2", response[1].Name) + + mockLocationService.AssertExpectations(t) +} diff --git a/core-service/internal/service/item_service_test.go b/core-service/internal/service/item_service_test.go new file mode 100644 index 0000000..d5df8ac --- /dev/null +++ b/core-service/internal/service/item_service_test.go @@ -0,0 +1,245 @@ +package service_test + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "erp-mvp/core-service/internal/models" + "erp-mvp/core-service/internal/service" +) + +// MockItemRepository мок для ItemRepository +type MockItemRepository struct { + mock.Mock +} + +func (m *MockItemRepository) Create(ctx context.Context, item *models.Item) error { + args := m.Called(ctx, item) + return args.Error(0) +} + +func (m *MockItemRepository) GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.Item, error) { + args := m.Called(ctx, id, orgID) + return args.Get(0).(*models.Item), args.Error(1) +} + +func (m *MockItemRepository) GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) { + args := m.Called(ctx, orgID) + return args.Get(0).([]*models.Item), args.Error(1) +} + +func (m *MockItemRepository) Update(ctx context.Context, item *models.Item) error { + args := m.Called(ctx, item) + return args.Error(0) +} + +func (m *MockItemRepository) Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error { + args := m.Called(ctx, id, orgID) + return args.Error(0) +} + +func (m *MockItemRepository) Search(ctx context.Context, orgID uuid.UUID, query string, category string) ([]*models.Item, error) { + args := m.Called(ctx, orgID, query, category) + return args.Get(0).([]*models.Item), args.Error(1) +} + +// TestNewItemService тестирует создание ItemService +func TestNewItemService(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + + // Act + itemService := service.NewItemService(mockRepo) + + // Assert + assert.NotNil(t, itemService) +} + +// TestItemService_GetItems_Success тестирует успешное получение товаров +func TestItemService_GetItems_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + expectedItems := []*models.Item{ + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Item 1", + Description: "Description 1", + Category: "electronics", + }, + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Item 2", + Description: "Description 2", + Category: "clothing", + }, + } + + mockRepo.On("GetByOrganization", mock.Anything, orgID).Return(expectedItems, nil) + + // Act + items, err := itemService.GetItems(context.Background(), orgID) + + // Assert + assert.NoError(t, err) + assert.Len(t, items, 2) + assert.Equal(t, "Item 1", items[0].Name) + assert.Equal(t, "Item 2", items[1].Name) + + mockRepo.AssertExpectations(t) +} + +// TestItemService_CreateItem_Success тестирует успешное создание товара +func TestItemService_CreateItem_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + req := &models.CreateItemRequest{ + Name: "New Item", + Description: "New Description", + Category: "electronics", + } + + mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*models.Item")).Return(nil) + + // Act + item, err := itemService.CreateItem(context.Background(), orgID, req) + + // Assert + assert.NoError(t, err) + assert.NotNil(t, item) + assert.Equal(t, "New Item", item.Name) + assert.Equal(t, "New Description", item.Description) + assert.Equal(t, "electronics", item.Category) + assert.Equal(t, orgID, item.OrganizationID) + + mockRepo.AssertExpectations(t) +} + +// TestItemService_GetItem_Success тестирует успешное получение товара по ID +func TestItemService_GetItem_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + itemID := uuid.New() + expectedItem := &models.Item{ + ID: itemID, + OrganizationID: orgID, + Name: "Test Item", + Description: "Test Description", + Category: "electronics", + } + + mockRepo.On("GetByID", mock.Anything, itemID, orgID).Return(expectedItem, nil) + + // Act + item, err := itemService.GetItem(context.Background(), itemID, orgID) + + // Assert + assert.NoError(t, err) + assert.NotNil(t, item) + assert.Equal(t, "Test Item", item.Name) + assert.Equal(t, itemID, item.ID) + + mockRepo.AssertExpectations(t) +} + +// TestItemService_SearchItems_Success тестирует успешный поиск товаров +func TestItemService_SearchItems_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + expectedItems := []*models.Item{ + { + ID: uuid.New(), + OrganizationID: orgID, + Name: "Search Result", + Description: "Found item", + Category: "electronics", + }, + } + + mockRepo.On("Search", mock.Anything, orgID, "search", "electronics").Return(expectedItems, nil) + + // Act + items, err := itemService.SearchItems(context.Background(), orgID, "search", "electronics") + + // Assert + assert.NoError(t, err) + assert.Len(t, items, 1) + assert.Equal(t, "Search Result", items[0].Name) + + mockRepo.AssertExpectations(t) +} + +// TestItemService_UpdateItem_Success тестирует успешное обновление товара +func TestItemService_UpdateItem_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + itemID := uuid.New() + req := &models.CreateItemRequest{ + Name: "Updated Item", + Description: "Updated Description", + Category: "clothing", + } + + existingItem := &models.Item{ + ID: itemID, + OrganizationID: orgID, + Name: "Old Item", + Description: "Old Description", + Category: "electronics", + } + + mockRepo.On("GetByID", mock.Anything, itemID, orgID).Return(existingItem, nil) + mockRepo.On("Update", mock.Anything, mock.AnythingOfType("*models.Item")).Return(nil) + + // Act + item, err := itemService.UpdateItem(context.Background(), itemID, orgID, req) + + // Assert + assert.NoError(t, err) + assert.NotNil(t, item) + assert.Equal(t, "Updated Item", item.Name) + assert.Equal(t, "Updated Description", item.Description) + assert.Equal(t, "clothing", item.Category) + + mockRepo.AssertExpectations(t) +} + +// TestItemService_DeleteItem_Success тестирует успешное удаление товара +func TestItemService_DeleteItem_Success(t *testing.T) { + // Arrange + mockRepo := &MockItemRepository{} + itemService := service.NewItemService(mockRepo) + + orgID := uuid.New() + itemID := uuid.New() + + mockRepo.On("Delete", mock.Anything, itemID, orgID).Return(nil) + + // Act + err := itemService.DeleteItem(context.Background(), itemID, orgID) + + // Assert + assert.NoError(t, err) + + mockRepo.AssertExpectations(t) +}