blob: 0cfeaea9f9960eceff2930704a65e7bbc0481503 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package ids
import (
"fmt"
"testing"
"time"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
idspb "go.chromium.org/turboci/proto/go/graph/ids/v1"
"go.chromium.org/turboci/proto/go/utils/internal/test/assert"
)
func TestCheckErr(t *testing.T) {
t.Run("ok", func(t *testing.T) {
cid, err := CheckErr("hello")
assert.NoErr(t, err)
assert.Match(t, idspb.Check_builder{
Id: proto.String("hello"),
}.Build(), cid)
})
t.Run("bad", func(t *testing.T) {
_, err := CheckErr("hello:world")
assert.ErrLike(t, err, `id.Check: id: "hello:world" contains ":"`)
})
}
func TestCheckResultErr(t *testing.T) {
t.Run("ok", func(t *testing.T) {
id, err := CheckResultErr("h", 1)
assert.NoErr(t, err)
assert.Match(t,
idspb.CheckResult_builder{
Check: idspb.Check_builder{Id: proto.String("h")}.Build(),
Idx: proto.Int32(1),
}.Build(),
id,
)
})
t.Run("bad checkid", func(t *testing.T) {
_, err := CheckResultErr("h:", 1)
assert.ErrLike(t, err, `id.CheckResult: id.Check: id: "h:" contains ":"`)
})
t.Run("bad idx", func(t *testing.T) {
_, err := CheckResultErr("h", 0)
assert.ErrLike(t, err, `id.CheckResult: resultIdx: 0 must be in [1, max(int32)]`)
})
}
func TestCheckEditErr(t *testing.T) {
ts := time.Unix(12345, 6789)
t.Run("ok", func(t *testing.T) {
id, err := CheckEditErr("h", ts)
assert.NoErr(t, err)
assert.Match(t,
idspb.CheckEdit_builder{
Check: idspb.Check_builder{Id: proto.String("h")}.Build(),
Version: timestamppb.New(ts),
}.Build(),
id,
)
})
t.Run("bad checkid", func(t *testing.T) {
_, err := CheckEditErr("h:", ts)
assert.ErrLike(t, err, `id.CheckEdit: id.Check: id: "h:" contains ":"`)
})
t.Run("bad ts", func(t *testing.T) {
_, err := CheckEditErr("h", time.Time{})
assert.ErrLike(t, err, `id.CheckEdit: zero timestamp`)
})
}
func TestStageErr(t *testing.T) {
t.Run("ok S", func(t *testing.T) {
id, err := StageErr(StageNotWorknode, "something")
assert.NoErr(t, err)
assert.Match(t,
idspb.Stage_builder{Id: proto.String("something"), IsWorknode: proto.Bool(false)}.Build(),
id,
)
})
t.Run("ok N", func(t *testing.T) {
id, err := StageErr(StageIsWorknode, "something")
assert.NoErr(t, err)
assert.Match(t,
idspb.Stage_builder{Id: proto.String("something"), IsWorknode: proto.Bool(true)}.Build(),
id,
)
})
t.Run("empty prefix", func(t *testing.T) {
_, err := StageErr(StageIsUnknown, "")
assert.ErrLike(t, err, `id.Stage: stageID: zero length`)
})
t.Run("bad format", func(t *testing.T) {
_, err := StageErr(StageIsUnknown, "some:thing")
assert.ErrLike(t, err, `id.Stage: stageID: "some:thing" contains ":"`)
})
}
func TestStageAttemptErr(t *testing.T) {
t.Run("ok", func(t *testing.T) {
id, err := StageAttemptErr(StageNotWorknode, "something", 1)
assert.NoErr(t, err)
assert.Match(t,
idspb.StageAttempt_builder{
Stage: idspb.Stage_builder{Id: proto.String("something"), IsWorknode: proto.Bool(false)}.Build(),
Idx: proto.Int32(1),
}.Build(),
id,
)
})
t.Run("bad idx", func(t *testing.T) {
_, err := StageAttemptErr(StageNotWorknode, "something", 0)
assert.ErrLike(t, err, `id.StageAttempt: attemptIdx: 0 must be in [1, max(int32)]`)
})
}
func TestStageEditErr(t *testing.T) {
ts := time.Unix(12345, 6789)
t.Run("ok", func(t *testing.T) {
id, err := StageEditErr(StageNotWorknode, "something", ts)
assert.NoErr(t, err)
assert.Match(t,
idspb.StageEdit_builder{
Stage: idspb.Stage_builder{
Id: proto.String("something"),
IsWorknode: proto.Bool(false),
}.Build(),
Version: timestamppb.New(ts),
}.Build(),
id,
)
})
t.Run("bad ts", func(t *testing.T) {
_, err := StageEditErr(StageNotWorknode, "something", time.Time{})
assert.ErrLike(t, err, `id.StageEdit: zero timestamp`)
})
}
func TestSetWorkplanErr(t *testing.T) {
t.Run("ok", func(t *testing.T) {
id, err := CheckErr("c")
assert.NoErr(t, err)
id, err = SetWorkplanErr(id, "Lwp")
assert.NoErr(t, err)
assert.Match(t,
idspb.Check_builder{
WorkPlan: idspb.WorkPlan_builder{Id: proto.String("Lwp")}.Build(),
Id: proto.String("c"),
}.Build(),
id,
)
})
t.Run("bad workplan", func(t *testing.T) {
id, err := CheckErr("c")
assert.NoErr(t, err)
_, err = SetWorkplanErr(id, "Lw:p")
assert.ErrLike(t, err, `id.SetWorkplan: workPlanID: "Lw:p" contains ":"`)
})
}
func TestSetWorkplan(t *testing.T) {
t.Run("ok", func(t *testing.T) {
id := SetWorkplan(must(CheckErr("c")), "Lwp")
assert.Match(t,
idspb.Check_builder{
WorkPlan: idspb.WorkPlan_builder{Id: proto.String("Lwp")}.Build(),
Id: proto.String("c"),
}.Build(),
id,
)
})
t.Run("panic", func(t *testing.T) {
assert.PanicLike(t, func() {
SetWorkplan(must(CheckErr("c")), "Lw:p")
}, `contains ":"`)
})
}
func TestStage(t *testing.T) {
t.Run(`ok`, func(t *testing.T) {
sid := Stage("hello")
assert.Match(t, idspb.Stage_builder{
Id: proto.String("hello"),
IsWorknode: proto.Bool(false),
}.Build(), sid)
})
t.Run("panic", func(t *testing.T) {
assert.PanicLike(t, func() {
Stage("")
}, `zero length`)
})
}
func ExampleSetWorkplan() {
id := SetWorkplan(Check("my-check"), "my-workplan")
fmt.Println(ToString(id))
// Output: Lmy-workplan:Cmy-check
}
func ExampleSetWorkplan_identifier() {
id := SetWorkplan(Wrap(Check("my-check")), "my-workplan")
fmt.Println(ToString(id))
// Output: Lmy-workplan:Cmy-check
}
func ExampleCheck() {
id := Check("my-check")
fmt.Println(ToString(id))
// Output: :Cmy-check
}
func ExampleStage() {
id := Stage("my-stage")
fmt.Println(ToString(id))
// Output: :Smy-stage
}
func ExampleStageUnknown() {
id := StageUnknown("my-stage")
fmt.Println(ToString(id))
// Output: :?my-stage
}
func ExampleStageWorkNode() {
id := StageWorkNode("my-stage")
fmt.Println(ToString(id))
// Output: :Nmy-stage
}
func ExampleWrap() {
cid := Check("my-check")
id := Wrap(cid)
fmt.Printf("%T --> %s\n", cid, ToString(cid))
fmt.Printf("%T --> %s\n", id, ToString(id))
// Output:
// *idspb.Check --> :Cmy-check
// *idspb.Identifier --> :Cmy-check
}