diff --git a/ids/format.go b/ids/format.go new file mode 100644 index 000000000000..5346167744a6 --- /dev/null +++ b/ids/format.go @@ -0,0 +1,48 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package ids + +import "fmt" + +var _ = []fmt.Formatter{ID{}, ShortID{}} + +// Format implements the [fmt.Formatter] interface. +func (id ID) Format(s fmt.State, verb rune) { + format(s, verb, id) +} + +// Format implements the [fmt.Formatter] interface. +func (id ShortID) Format(s fmt.State, verb rune) { + format(s, verb, id) +} + +type idForFormatting interface { + String() string + Hex() string +} + +// format implements the [fmt.Formatter] interface for [ID] and [ShortID]. +func format[T interface { + idForFormatting + ID | ShortID +}](s fmt.State, verb rune, id T) { + switch verb { + case 'x': + if s.Flag('#') { + s.Write([]byte("0x")) //nolint:errcheck // [fmt.Formatter] doesn't allow for returning errors, and the implementation of [fmt.State] always returns nil on Write() + } + s.Write([]byte(id.Hex())) //nolint:errcheck // See above + + case 'q': + str := id.String() + buf := make([]byte, len(str)+2) + buf[0] = '"' + buf[len(buf)-1] = '"' + copy(buf[1:], str) + s.Write(buf) //nolint:errcheck // See above + + default: + s.Write([]byte(id.String())) //nolint:errcheck // See above + } +} diff --git a/ids/format_test.go b/ids/format_test.go new file mode 100644 index 000000000000..07837f6b9442 --- /dev/null +++ b/ids/format_test.go @@ -0,0 +1,47 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package ids + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFormat(t *testing.T) { + type test struct { + id idForFormatting + want map[string]string // format -> output + } + makeTestCase := func(id idForFormatting) test { + return test{ + id: id, + want: map[string]string{ + "%v": id.String(), + "%s": id.String(), + "%q": `"` + id.String() + `"`, + "%x": id.Hex(), + "%#x": `0x` + id.Hex(), + }, + } + } + + tests := []test{ + makeTestCase(ID{}), + makeTestCase(GenerateTestID()), + makeTestCase(GenerateTestID()), + makeTestCase(ShortID{}), + makeTestCase(GenerateTestShortID()), + makeTestCase(GenerateTestShortID()), + } + + for _, tt := range tests { + t.Run(tt.id.String(), func(t *testing.T) { + for format, want := range tt.want { + require.Equalf(t, want, fmt.Sprintf(format, tt.id), "fmt.Sprintf(%q, %T)", format, tt.id) + } + }) + } +}