Skip to content

Commit

Permalink
change AsSlice to String on label set and add json tags
Browse files Browse the repository at this point in the history
  • Loading branch information
eutopian committed Jan 31, 2025
1 parent 76fa418 commit 7a2e61d
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 62 deletions.
26 changes: 11 additions & 15 deletions deployment/address_book.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package deployment

import (
"fmt"
"sort"
"strings"
"sync"

Expand Down Expand Up @@ -33,21 +32,22 @@ var (
)

type TypeAndVersion struct {
Type ContractType
Version semver.Version
Labels LabelSet
Type ContractType `json:"type"`
Version semver.Version `json:"version"`
Labels LabelSet `json:"labels,omitempty"`
}

func (tv TypeAndVersion) String() string {
if len(tv.Labels) == 0 {
return fmt.Sprintf("%s %s", tv.Type, tv.Version.String())
}
mdSlice := tv.Labels.AsSlice()
sort.Strings(mdSlice) // stable order

// Use the LabelSet's String method for sorted labels
sortedLabels := tv.Labels.String()
return fmt.Sprintf("%s %s %s",
tv.Type,
tv.Version.String(),
strings.Join(mdSlice, " "),
sortedLabels,
)
}

Expand Down Expand Up @@ -307,15 +307,11 @@ type typeVersionKey struct {
}

func tvKey(tv TypeAndVersion) typeVersionKey {
sortedLabels := make([]string, 0, len(tv.Labels))
for lbl := range tv.Labels {
sortedLabels = append(sortedLabels, lbl)
}
sort.Strings(sortedLabels)
sortedLabels := tv.Labels.String()
return typeVersionKey{
Type: tv.Type,
Version: tv.Version.String(),
Labels: strings.Join(sortedLabels, ","),
Labels: sortedLabels,
}
}

Expand All @@ -332,8 +328,8 @@ func AddressesContainBundle(addrs map[string]TypeAndVersion, wantTypes []TypeAnd
// They match exactly (Type, Version, Labels)
counts[wantKey]++
if counts[wantKey] > 1 {
return false, fmt.Errorf("found more than one instance of contract %s %s (labels=%v)",
wantTV.Type, wantTV.Version.String(), wantTV.Labels)
return false, fmt.Errorf("found more than one instance of contract %s %s (labels=%s)",
wantTV.Type, wantTV.Version.String(), wantTV.Labels.String())
}
}
}
Expand Down
28 changes: 22 additions & 6 deletions deployment/address_book_labels.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package deployment

import (
"sort"
"strings"
)

// LabelSet represents a set of labels on an address book entry.
type LabelSet map[string]struct{}

Expand Down Expand Up @@ -28,13 +33,24 @@ func (ls LabelSet) Contains(labels string) bool {
return ok
}

// AsSlice returns the labels in a slice. Useful for printing or serialization.
func (ls LabelSet) AsSlice() []string {
out := make([]string, 0, len(ls))
for labels := range ls {
out = append(out, labels)
// String returns the labels as a sorted, space-separated string.
// It implements the fmt.Stringer interface.
func (ls LabelSet) String() string {
if len(ls) == 0 {
return ""
}

// Collect labels into a slice
labels := make([]string, 0, len(ls))
for label := range ls {
labels = append(labels, label)
}
return out

// Sort the labels to ensure consistent ordering
sort.Strings(labels)

// Concatenate the sorted labels into a single string
return strings.Join(labels, " ")
}

// Equal checks if two LabelSets are equal.
Expand Down
61 changes: 49 additions & 12 deletions deployment/address_book_labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,57 @@ func TestLabelSet_Contains(t *testing.T) {
assert.False(t, ms.Contains("baz"))
}

func TestLabelSet_AsSlice(t *testing.T) {
ms := NewLabelSet("foo", "bar")
slice := ms.AsSlice()

// We can't rely on order in a map-based set, so we only check membership and length
assert.Len(t, slice, 2, "expected 2 distinct labels in slice")
// TestLabelSet_String tests the String() method of the LabelSet type.
func TestLabelSet_String(t *testing.T) {
tests := []struct {
name string
labels LabelSet
expected string
}{
{
name: "Empty LabelSet",
labels: NewLabelSet(),
expected: "",
},
{
name: "Single label",
labels: NewLabelSet("alpha"),
expected: "alpha",
},
{
name: "Multiple labels in random order",
labels: NewLabelSet("beta", "gamma", "alpha"),
expected: "alpha beta gamma",
},
{
name: "Labels with special characters",
labels: NewLabelSet("beta", "gamma!", "@alpha"),
expected: "@alpha beta gamma!",
},
{
name: "Labels with spaces",
labels: NewLabelSet("beta", "gamma delta", "alpha"),
expected: "alpha beta gamma delta",
},
{
name: "Labels added in different orders",
labels: NewLabelSet("delta", "beta", "alpha"),
expected: "alpha beta delta",
},
{
name: "Labels with duplicate additions",
labels: NewLabelSet("alpha", "beta", "alpha", "gamma", "beta"),
expected: "alpha beta gamma",
},
}

// Convert slice to a map for quick membership checks
found := make(map[string]bool)
for _, item := range slice {
found[item] = true
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
result := tt.labels.String()
assert.Equal(t, tt.expected, result, "LabelSet.String() should return the expected sorted string")
})
}
assert.True(t, found["foo"], "expected 'foo' in slice")
assert.True(t, found["bar"], "expected 'bar' in slice")
}

func TestLabelSet_Equal(t *testing.T) {
Expand Down
61 changes: 32 additions & 29 deletions deployment/address_book_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,36 +356,40 @@ func TestTypeAndVersionFromString(t *testing.T) {
t.Parallel()

tests := []struct {
name string
input string
wantErr bool
wantType ContractType
wantVersion semver.Version
wantMeta []string
name string
input string
wantErr bool
wantType ContractType
wantVersion semver.Version
wantLabels LabelSet
wantTypeAndVersion string
}{
{
name: "valid - no labels",
input: "CallProxy 1.0.0",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantMeta: nil, // no labels
name: "valid - no labels",
input: "CallProxy 1.0.0",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantLabels: NewLabelSet(),
wantTypeAndVersion: "CallProxy 1.0.0",
},
{
name: "valid - multiple labels, normal spacing",
input: "CallProxy 1.0.0 SA staging",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantMeta: []string{"SA", "staging"},
name: "valid - multiple labels, normal spacing",
input: "CallProxy 1.0.0 SA staging",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantLabels: NewLabelSet("SA", "staging"),
wantTypeAndVersion: "CallProxy 1.0.0 SA staging",
},
{
name: "valid - multiple labels, extra spacing",
input: " CallProxy 1.0.0 SA staging ",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantMeta: []string{"SA", "staging"},
name: "valid - multiple labels, extra spacing",
input: " CallProxy 1.0.0 SA staging ",
wantErr: false,
wantType: "CallProxy",
wantVersion: Version1_0_0,
wantLabels: NewLabelSet("SA", "staging"),
wantTypeAndVersion: "CallProxy 1.0.0 SA staging",
},
{
name: "invalid - not enough parts",
Expand Down Expand Up @@ -418,11 +422,10 @@ func TestTypeAndVersionFromString(t *testing.T) {
require.Equal(t, tt.wantVersion.String(), gotTV.Version.String(), "incorrect version")

// Check labels
gotMeta := gotTV.Labels.AsSlice()
require.Equal(t, len(tt.wantMeta), len(gotMeta), "labels length mismatch")
for _, wantMd := range tt.wantMeta {
require.Contains(t, gotMeta, wantMd, "missing labels item")
}
require.Equal(t, tt.wantLabels, gotTV.Labels, "labels mismatch")

// Check type and version
require.Equal(t, tt.wantTypeAndVersion, gotTV.String(), "type and version mismatch")
})
}
}
Expand Down

0 comments on commit 7a2e61d

Please sign in to comment.