diff --git a/internal/service/ops.go b/internal/service/ops.go index dabb90f..53d2b93 100644 --- a/internal/service/ops.go +++ b/internal/service/ops.go @@ -218,6 +218,10 @@ func (s *Service) Fill(ctx context.Context, actorID, objectID int64, spec FillSp if region, err = NamedRegion(o, spec.RegionName); err != nil { return nil, err } + } else if !(region.MinX < region.MaxX && region.MinY < region.MaxY) { + // A zero or inverted rectangle is a caller that said nothing about where + // — not a request for the one plop hexCenters would put at its middle. + return nil, fmt.Errorf("%w: the fill rectangle is empty", domain.ErrInvalidInput) } return s.fillLoaded(ctx, actorID, o, region, spec) } @@ -673,11 +677,13 @@ func (s *Service) ListObjectPlantings(ctx context.Context, actorID, objectID int plant, ok := plants[pl.PlantID] if !ok { p, err := s.store.GetPlant(ctx, pl.PlantID) - if err != nil { + if err != nil && !errors.Is(err, domain.ErrNotFound) { return nil, err } - plant = *p - plants[pl.PlantID] = plant + if p != nil { + plant = *p + } + plants[pl.PlantID] = plant // a plant that no longer exists lists unnamed, not as an error } pl.DerivedCount = derivedCount(pl.RadiusCM, plant.SpacingCM) out = append(out, describePlanting(pl, plant.Name)) diff --git a/internal/service/ops_test.go b/internal/service/ops_test.go index 78c1f34..a803ae8 100644 --- a/internal/service/ops_test.go +++ b/internal/service/ops_test.go @@ -790,4 +790,11 @@ func TestFillByRectangleAttributesSeed(t *testing.T) { if _, err := s.Fill(ctx, owner, bed.ID, FillSpec{RegionName: "all", PlantID: garlic.ID, SeedLotID: &lot.ID}); err == nil { t.Error("a fill charged to a lot of a different plant succeeded") } + // No name and no rectangle is "nowhere", not "one plop in the middle" (which + // is what hexCenters makes of a zero-area region). + for _, r := range []Region{{}, {MinX: 10, MinY: -10, MaxX: 10, MaxY: 10}, {MinX: 20, MinY: 0, MaxX: -20, MaxY: 10}} { + if _, err := s.Fill(ctx, owner, bed.ID, FillSpec{Region: r, PlantID: garlic.ID}); !errors.Is(err, domain.ErrInvalidInput) { + t.Errorf("empty rectangle %+v: err = %v, want ErrInvalidInput", r, err) + } + } }