189 lines
5.3 KiB
Go
189 lines
5.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"history-api/internal/dtos/request"
|
|
"history-api/internal/dtos/response"
|
|
"history-api/internal/gen/sqlc"
|
|
"history-api/internal/models"
|
|
"history-api/internal/repositories"
|
|
"testing"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
// mockGeometryRepository implements repositories.GeometryRepository for unit testing
|
|
type mockGeometryRepository struct {
|
|
mockGeometries []*models.GeometryEntity
|
|
mockErr error
|
|
}
|
|
|
|
func (m *mockGeometryRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models.GeometryEntity, error) {
|
|
if m.mockErr != nil {
|
|
return nil, m.mockErr
|
|
}
|
|
if len(m.mockGeometries) > 0 {
|
|
return m.mockGeometries[0], nil
|
|
}
|
|
return nil, errors.New("not found")
|
|
}
|
|
|
|
func (m *mockGeometryRepository) GetByIDs(ctx context.Context, ids []string) ([]*models.GeometryEntity, error) {
|
|
return m.mockGeometries, m.mockErr
|
|
}
|
|
|
|
func (m *mockGeometryRepository) Search(ctx context.Context, params sqlc.SearchGeometriesParams) ([]*models.GeometryEntity, error) {
|
|
return m.mockGeometries, m.mockErr
|
|
}
|
|
|
|
func (m *mockGeometryRepository) SearchByEntityName(ctx context.Context, params sqlc.SearchGeometriesByEntityNameParams) ([]*models.EntityGeometriesSearchEntity, error) {
|
|
return nil, m.mockErr
|
|
}
|
|
|
|
func (m *mockGeometryRepository) Create(ctx context.Context, params sqlc.CreateGeometryParams) (*models.GeometryEntity, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) Update(ctx context.Context, params sqlc.UpdateGeometryParams) (*models.GeometryEntity, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) Delete(ctx context.Context, id pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) CreateEntityGeometries(ctx context.Context, params sqlc.CreateEntityGeometriesParams) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) BulkDeleteEntityGeometriesByEntityId(ctx context.Context, entityId pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.GeometryEntity, error) {
|
|
return m.mockGeometries, m.mockErr
|
|
}
|
|
|
|
func (m *mockGeometryRepository) GetGeometriesByBoundWith(ctx context.Context, boundWith pgtype.UUID) ([]*models.GeometryEntity, error) {
|
|
return m.mockGeometries, m.mockErr
|
|
}
|
|
|
|
func (m *mockGeometryRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) BulkDeleteEntityGeometriesByGeometryID(ctx context.Context, geometryID pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) DeleteEntityGeometry(ctx context.Context, entityID pgtype.UUID, geometryID pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) DeleteEntityGeometriesByProjectID(ctx context.Context, projectID pgtype.UUID) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockGeometryRepository) WithTx(tx pgx.Tx) repositories.GeometryRepository {
|
|
return m
|
|
}
|
|
|
|
// Helper to float pointer
|
|
func floatPtr(f float64) *float64 {
|
|
return &f
|
|
}
|
|
|
|
// Helper to int pointer
|
|
func intPtr(i int32) *int32 {
|
|
return &i
|
|
}
|
|
|
|
func TestGetGeometryByID_InvalidID(t *testing.T) {
|
|
repo := &mockGeometryRepository{}
|
|
svc := NewGeometryService(repo)
|
|
|
|
_, fErr := svc.GetGeometryByID(context.Background(), "invalid-uuid-format")
|
|
if fErr == nil {
|
|
t.Fatal("Expected error for invalid UUID format, got nil")
|
|
}
|
|
if fErr.Code != 400 {
|
|
t.Errorf("Expected status 400, got %d", fErr.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchGeometries_NoBoundingBox(t *testing.T) {
|
|
repo := &mockGeometryRepository{}
|
|
svc := NewGeometryService(repo)
|
|
|
|
req := &request.SearchGeometryDto{
|
|
MinLng: nil, // Missing bounding box parameters
|
|
}
|
|
|
|
_, fErr := svc.SearchGeometries(context.Background(), req)
|
|
if fErr == nil {
|
|
t.Fatal("Expected error for missing bounding box, got nil")
|
|
}
|
|
if fErr.Code != 400 {
|
|
t.Errorf("Expected status 400, got %d", fErr.Code)
|
|
}
|
|
}
|
|
|
|
func TestSearchGeometries_InvalidBoundingBox(t *testing.T) {
|
|
repo := &mockGeometryRepository{}
|
|
svc := NewGeometryService(repo)
|
|
|
|
req := &request.SearchGeometryDto{
|
|
MinLng: floatPtr(105.0),
|
|
MinLat: floatPtr(21.0),
|
|
MaxLng: floatPtr(100.0), // MaxLng < MinLng (Invalid)
|
|
MaxLat: floatPtr(22.0),
|
|
}
|
|
|
|
_, fErr := svc.SearchGeometries(context.Background(), req)
|
|
if fErr == nil {
|
|
t.Fatal("Expected error for invalid bounding box coordinates, got nil")
|
|
}
|
|
if fErr.Code != 400 {
|
|
t.Errorf("Expected status 400, got %d", fErr.Code)
|
|
}
|
|
if fErr.Message != "Invalid bounding box coordinates" {
|
|
t.Errorf("Expected error message 'Invalid bounding box coordinates', got '%s'", fErr.Message)
|
|
}
|
|
}
|
|
|
|
func TestSearchGeometries_Valid(t *testing.T) {
|
|
mockGeometries := []*models.GeometryEntity{
|
|
{
|
|
ID: "87570494-0cfb-4e14-8789-7cfc0245037d",
|
|
GeoType: 3, // Polygon
|
|
Bbox: &response.Bbox{
|
|
MinLng: 102.0, MinLat: 8.0, MaxLng: 109.0, MaxLat: 23.0,
|
|
},
|
|
},
|
|
}
|
|
repo := &mockGeometryRepository{
|
|
mockGeometries: mockGeometries,
|
|
}
|
|
svc := NewGeometryService(repo)
|
|
|
|
req := &request.SearchGeometryDto{
|
|
MinLng: floatPtr(100.0),
|
|
MinLat: floatPtr(5.0),
|
|
MaxLng: floatPtr(110.0),
|
|
MaxLat: floatPtr(25.0),
|
|
}
|
|
|
|
res, fErr := svc.SearchGeometries(context.Background(), req)
|
|
if fErr != nil {
|
|
t.Fatalf("Expected no error, got %v", fErr)
|
|
}
|
|
if len(res) != 1 {
|
|
t.Fatalf("Expected 1 geometry response, got %d", len(res))
|
|
}
|
|
if res[0].ID != mockGeometries[0].ID {
|
|
t.Errorf("Expected ID %s, got %s", mockGeometries[0].ID, res[0].ID)
|
|
}
|
|
}
|