Naming, layout and comments: descriptive full-word names, one item per line in wrapped calls and literals, and doc comments on exported names

Short and single-letter names in application code become full words (tests
keep theirs). Wrapped calls, signatures and composite literals put one item
per line, and one-line function bodies are expanded. Exported names and
groups of constants get doc comments, and comments refer to the renamed
identifiers.
This commit is contained in:
bwilliams committed 2026-10-15 16:12:56 +01:00
1 parent 043e307663
commit 465358609a
78 files changed
+2374 -1402

No files matched your search

+82 -77
View File
@@ -23,12 +23,12 @@ type Generator struct {
opts options
}
// NewGenerator returns a generator drawing from cat and storing releases in
// NewGenerator returns a generator drawing from catalog and storing releases in
// store. The same seed and store contents give the same releases. It logs to
// slog.Default() unless given WithLogger.
func NewGenerator(cat *Catalog, store *Store, seed int64, opts ...Option) *Generator {
func NewGenerator(catalog *Catalog, store *Store, seed int64, opts ...Option) *Generator {
return &Generator{
cat: cat,
cat: catalog,
store: store,
rnd: rand.New(rand.NewSource(seed)), //nolint:gosec // seeded for repeatable mock data
opts: applyOptions(opts),
@@ -56,7 +56,7 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
buyer := g.cat.buyer(g.rnd)
ensurePartyID(&buyer)
buyer.Roles = []string{"buyer"}
m := g.cat.method(g.rnd)
method := g.cat.method(g.rnd)
tag, status := "tender", "active"
if g.rnd.Float64() < 0.2 {
@@ -64,38 +64,38 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
}
ocid := g.newOCID()
t := g.cat.subject(g.rnd)
t.ID = ocds.ID(ocid)
t.ProcurementMethod = m.Method
t.ProcurementMethodDetails = m.Details
tender := g.cat.subject(g.rnd)
tender.ID = ocds.ID(ocid)
tender.ProcurementMethod = method.Method
tender.ProcurementMethodDetails = method.Details
factor := 0.5 + g.rnd.Float64()*1.5
if t.Value == nil {
if tender.Value == nil {
amount := float64((g.rnd.Intn(5000) + 10) * 1000)
t.Value = &ocds.Value{
tender.Value = &ocds.Value{
Amount: &amount,
Currency: "GBP",
}
} else {
scaleValue(t.Value, factor)
scaleValue(tender.Value, factor)
}
for i := range t.Lots {
scaleValue(t.Lots[i].Value, factor)
for i := range tender.Lots {
scaleValue(tender.Lots[i].Value, factor)
}
if len(t.Lots) == 0 {
v := clone(*t.Value)
t.Lots = []ocds.Lot{{
if len(tender.Lots) == 0 {
value := clone(*tender.Value)
tender.Lots = []ocds.Lot{{
ID: "1",
Title: t.Title,
Value: &v,
Title: tender.Title,
Value: &value,
}}
}
setStatus(&t, status)
setStatus(&tender, status)
if status == "active" {
t.TenderPeriod = &ocds.Period{
tender.TenderPeriod = &ocds.Period{
EndDate: ptr(at.AddDate(0, 0, 30+g.rnd.Intn(30))),
}
}
@@ -111,7 +111,7 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
ID: ocds.ID(buyer.ID),
Name: buyer.Name,
},
Tender: &t,
Tender: &tender,
Language: "en",
}
}
@@ -120,13 +120,13 @@ func (g *Generator) newProcedure(at time.Time) ocds.Release {
// tender, and a tender either has its deadline extended (tenderUpdate) or is
// awarded to a supplier from the catalog.
func (g *Generator) advance(prev ocds.Release, at time.Time) ocds.Release {
r := clone(prev)
r.ID = g.store.NextNoticeID(at.Year())
r.Date = at
r.Awards = nil
if r.Tender == nil {
r.Tender = &ocds.Tender{
ID: ocds.ID(r.OCID),
release := clone(prev)
release.ID = g.store.NextNoticeID(at.Year())
release.Date = at
release.Awards = nil
if release.Tender == nil {
release.Tender = &ocds.Tender{
ID: ocds.ID(release.OCID),
}
}
@@ -139,60 +139,60 @@ func (g *Generator) advance(prev ocds.Release, at time.Time) ocds.Release {
next = "tenderUpdate"
}
}
r.Tag = []string{next}
release.Tag = []string{next}
switch next {
case "tender":
setStatus(r.Tender, "active")
r.Tender.TenderPeriod = &ocds.Period{
setStatus(release.Tender, "active")
release.Tender.TenderPeriod = &ocds.Period{
EndDate: ptr(at.AddDate(0, 0, 30+g.rnd.Intn(30))),
}
case "tenderUpdate":
// A typical update: the deadline is extended by two weeks.
end := at.AddDate(0, 0, 30)
if tp := r.Tender.TenderPeriod; tp != nil && tp.EndDate != nil {
end = *tp.EndDate
if period := release.Tender.TenderPeriod; period != nil && period.EndDate != nil {
end = *period.EndDate
}
r.Tender.TenderPeriod = &ocds.Period{
release.Tender.TenderPeriod = &ocds.Period{
EndDate: ptr(end.AddDate(0, 0, 14)),
}
case "award":
setStatus(r.Tender, "complete")
sup := g.cat.supplier(g.rnd)
ensurePartyID(&sup)
sup.Roles = []string{"supplier"}
r.Parties = append(r.Parties, sup)
setStatus(release.Tender, "complete")
supplier := g.cat.supplier(g.rnd)
ensurePartyID(&supplier)
supplier.Roles = []string{"supplier"}
release.Parties = append(release.Parties, supplier)
var value *ocds.Value
if r.Tender.Value != nil {
v := clone(*r.Tender.Value)
scaleValue(&v, 0.8+g.rnd.Float64()*0.2)
value = &v
if release.Tender.Value != nil {
scaled := clone(*release.Tender.Value)
scaleValue(&scaled, 0.8+g.rnd.Float64()*0.2)
value = &scaled
}
var lotIDs []string
for _, lot := range r.Tender.Lots {
for _, lot := range release.Tender.Lots {
if lot.ID != "" {
lotIDs = append(lotIDs, lot.ID)
}
}
r.Awards = []ocds.Award{{
release.Awards = []ocds.Award{{
ID: "1",
Status: "active",
Date: ptr(at),
Value: value,
Suppliers: []ocds.OrganizationReference{
{
ID: ocds.ID(sup.ID),
Name: sup.Name,
ID: ocds.ID(supplier.ID),
Name: supplier.Name,
},
},
RelatedLots: lotIDs,
}}
}
return r
return release
}
// newOCID returns a random ocid not already in the store.
@@ -224,25 +224,25 @@ func (g *Generator) CatchUp(
start = last
}
n := 0
for t := start.Add(g.gap(min, max)); !t.After(now); t = t.Add(g.gap(min, max)) {
if err := g.store.AppendNoSync(g.Make(t)); err != nil {
return n, err
count := 0
for when := start.Add(g.gap(min, max)); !when.After(now); when = when.Add(g.gap(min, max)) {
if err := g.store.AppendNoSync(g.Make(when)); err != nil {
return count, err
}
n++
count++
}
return n, g.store.Sync()
return count, g.store.Sync()
}
// Run publishes a new release after a random gap between min and max until ctx ends.
func (g *Generator) Run(ctx context.Context, min, max time.Duration) {
logger := g.opts.logger("generator")
for {
d := g.gap(min, max)
logger.Info("next release", "in", d.Round(time.Second))
gap := g.gap(min, max)
logger.Info("next release", "in", gap.Round(time.Second))
timer := time.NewTimer(d)
timer := time.NewTimer(gap)
select {
case <-ctx.Done():
timer.Stop()
@@ -250,46 +250,51 @@ func (g *Generator) Run(ctx context.Context, min, max time.Duration) {
case <-timer.C:
}
r := g.Make(time.Now())
if err := g.store.Append(r); err != nil {
release := g.Make(time.Now())
if err := g.store.Append(release); err != nil {
logger.Error("storing release failed", "error", err)
continue
}
logger.Info("published release", "release_id", r.ID, "tag", r.Tag[0], "ocid", r.OCID)
logger.Info(
"published release",
"release_id", release.ID,
"tag", release.Tag[0],
"ocid", release.OCID,
)
}
}
// ---------- helpers ----------
func ptr[T any](v T) *T { return &v }
func ptr[T any](value T) *T { return &value }
func setStatus(t *ocds.Tender, status string) {
t.Status = status
for i := range t.Lots {
t.Lots[i].Status = status
func setStatus(tender *ocds.Tender, status string) {
tender.Status = status
for i := range tender.Lots {
tender.Lots[i].Status = status
}
}
// scaleValue multiplies v's amounts by f, rounded to the nearest 100.
func scaleValue(v *ocds.Value, f float64) {
if v == nil {
// scaleValue multiplies value's amounts by factor, rounded to the nearest 100.
func scaleValue(value *ocds.Value, factor float64) {
if value == nil {
return
}
for _, a := range []**float64{&v.Amount, &v.AmountGross} {
if *a != nil {
*a = ptr(math.Round(**a*f/100) * 100)
for _, amount := range []**float64{&value.Amount, &value.AmountGross} {
if *amount != nil {
*amount = ptr(math.Round(**amount*factor/100) * 100)
}
}
}
// ensurePartyID gives p an id derived from its name if it has none, so the
// ensurePartyID gives party an id derived from its name if it has none, so the
// same organisation always gets the same id.
func ensurePartyID(p *ocds.Organization) {
if p.ID != "" {
func ensurePartyID(party *ocds.Organization) {
if party.ID != "" {
return
}
h := fnv.New32a()
h.Write([]byte(p.Name)) //nolint:gosec // never fails
p.ID = fmt.Sprintf("GB-FTS-%d", h.Sum32()%1000000)
hasher := fnv.New32a()
hasher.Write([]byte(party.Name)) //nolint:gosec // never fails
party.ID = fmt.Sprintf("GB-FTS-%d", hasher.Sum32()%1000000)
}