From f167a9d53145b661d05ac28b5702b6f29ea9c502 Mon Sep 17 00:00:00 2001 From: Yoshiyuki Mineo Date: Sat, 5 Jul 2025 17:50:03 +0900 Subject: [PATCH] Add Compose method and corresponding tests (#79) * Implemented the Compose function to create a Sonyflake ID from its components, including validation for start time, sequence, and machine ID. * Added a new test, TestCompose, to verify the functionality of the Compose method, ensuring correct decomposition of generated IDs. * Introduced a new error for invalid sequence numbers to enhance error handling in the Sonyflake package. --- sonyflake.go | 20 ++++++++++++++++++++ sonyflake_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/sonyflake.go b/sonyflake.go index 2db3325..84fbd28 100644 --- a/sonyflake.go +++ b/sonyflake.go @@ -57,6 +57,7 @@ var ( ErrNoPrivateAddress = errors.New("no private ip address") ErrOverTimeLimit = errors.New("over the time limit") ErrInvalidMachineID = errors.New("invalid machine id") + ErrInvalidSequence = errors.New("invalid sequence number") ) var defaultInterfaceAddrs = net.InterfaceAddrs @@ -213,6 +214,25 @@ func MachineID(id uint64) uint64 { return id & maskMachineID } +// Compose creates a Sonyflake ID from its parts. +func Compose(sf *Sonyflake, t time.Time, sequence uint16, machineID uint16) (uint64, error) { + elapsedTime := toSonyflakeTime(t.UTC()) - sf.startTime + if elapsedTime < 0 { + return 0, ErrStartTimeAhead + } + if elapsedTime >= 1<= 1<> 63 diff --git a/sonyflake_test.go b/sonyflake_test.go index 98f8552..b3e1045 100644 --- a/sonyflake_test.go +++ b/sonyflake_test.go @@ -312,3 +312,36 @@ func TestSonyflakeTimeUnit(t *testing.T) { t.Errorf("unexpected time unit") } } + +func TestCompose(t *testing.T) { + var st Settings + st.StartTime = time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC) + sf, err := New(st) + if err != nil { + t.Fatal(err) + } + + now := time.Now() + sequence := uint16(123) + machineID := uint16(456) + + id, err := Compose(sf, now, sequence, machineID) + if err != nil { + t.Fatal(err) + } + + parts := Decompose(id) + + actualTime := toSonyflakeTime(now) - toSonyflakeTime(st.StartTime) + if parts["time"] != uint64(actualTime) { + t.Errorf("unexpected time: %d", parts["time"]) + } + + if parts["sequence"] != uint64(sequence) { + t.Errorf("unexpected sequence: %d", parts["sequence"]) + } + + if parts["machine-id"] != uint64(machineID) { + t.Errorf("unexpected machine id: %d", parts["machine-id"]) + } +}