material_manage_system/internal/service/inventory_scope_test.go
2026-10-09 11:10:13 +08:00

89 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"errors"
"strings"
"testing"
"github.com/DATA-DOG/go-sqlmock"
)
// expectWarehouseSummary 让 WarehouseRepository.List 返回一组仓库/库位,用于驱动
// ResolveInventoryScope。传 nil 表示"该公司没有仓库"。
func expectWarehouseSummary(mock sqlmock.Sqlmock, organizationID int64, warehouseStatus, locationStatus *string) {
rows := sqlmock.NewRows([]string{"id", "organization_id", "code", "name", "status", "location_id", "location_code", "location_name", "location_status"})
if warehouseStatus != nil {
var locationID interface{} = nil
var locationCode, locationName, locStatus interface{} = nil, nil, nil
if locationStatus != nil {
locationID, locationCode, locationName, locStatus = 20, "L", "库位", *locationStatus
}
rows.AddRow(10, organizationID, "W", "仓库", *warehouseStatus, locationID, locationCode, locationName, locStatus)
}
mock.ExpectQuery("SELECT w.id, w.organization_id").WithArgs(organizationID).WillReturnRows(rows)
}
func strptr(s string) *string { return &s }
func TestResolveInventoryScopeUnavailableCases(t *testing.T) {
cases := []struct {
name string
warehouseStatus *string
locationStatus *string
requireActive bool
wantSubstring string
}{
{"no warehouse", nil, nil, true, "请先配置本公司仓库"},
{"no location", strptr("active"), nil, true, "请先配置本公司仓库的库位"},
{"disabled warehouse", strptr("inactive"), strptr("active"), true, "本公司仓库已停用"},
{"disabled location", strptr("active"), strptr("inactive"), true, "本公司库位已停用"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
mock := outboundMock(t)
expectWarehouseSummary(mock, 1, tc.warehouseStatus, tc.locationStatus)
_, err := ResolveInventoryScope(1, tc.requireActive)
if !errors.Is(err, ErrInventoryScopeUnavailable) {
t.Fatalf("got %v, want ErrInventoryScopeUnavailable", err)
}
if !strings.Contains(err.Error(), tc.wantSubstring) {
t.Fatalf("message %q must contain %q", err.Error(), tc.wantSubstring)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
})
}
}
func TestResolveInventoryScopeReturnsActiveDimensions(t *testing.T) {
mock := outboundMock(t)
expectWarehouseSummary(mock, 3, strptr("active"), strptr("active"))
scope, err := ResolveInventoryScope(3, true)
if err != nil {
t.Fatalf("resolve scope: %v", err)
}
if scope.OrganizationID != 3 || scope.WarehouseID != 10 || scope.LocationID != 20 {
t.Fatalf("scope=%+v, want 3/10/20", scope)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}
// 只读场景(requireActive=false):停用的仓库、库位仍返回其维度,方便核验历史余额。
func TestResolveInventoryScopeKeepsDisabledDimensionsForReads(t *testing.T) {
mock := outboundMock(t)
expectWarehouseSummary(mock, 1, strptr("inactive"), strptr("inactive"))
scope, err := ResolveInventoryScope(1, false)
if err != nil {
t.Fatalf("resolve scope for reads: %v", err)
}
if scope.WarehouseID != 10 || scope.LocationID != 20 {
t.Fatalf("scope=%+v, want disabled dimensions preserved", scope)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}