blob: 5926919e8fc2f87b7db9257c32af1895c0a5be78 [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 value
import (
"slices"
"testing"
orchestratorpb "go.chromium.org/turboci/proto/go/graph/orchestrator/v1"
"go.chromium.org/turboci/proto/go/internal/test/assert"
)
func TestValueSlotSet(t *testing.T) {
t.Parallel()
t.Run("zero_value", func(t *testing.T) {
t.Parallel()
var s SlotSet
assert.Equal(t, uint64(0), s.val)
assert.Empty(t, slices.Collect(s.Range()))
assert.Equal(t, "value.SlotSet{}", s.String())
assert.False(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
assert.False(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
})
t.Run("set_unset_immutability", func(t *testing.T) {
t.Parallel()
var s1 SlotSet
s2 := s1.Set(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS)
assert.Equal(t, uint64(0), s1.val)
assert.Equal(t, uint64((1<<0)|(1<<5)), s2.val)
s3 := s2.Unset(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION)
assert.Equal(t, uint64((1<<0)|(1<<5)), s2.val)
assert.Equal(t, uint64(1<<5), s3.val)
})
t.Run("containment", func(t *testing.T) {
t.Parallel()
s := SlotSet{}.Set(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS)
assert.True(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
assert.True(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS))
assert.False(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA))
assert.True(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
assert.True(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA))
assert.False(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA))
})
t.Run("unknown_and_duplicates", func(t *testing.T) {
t.Parallel()
s := SlotSet{}.Set(
orchestratorpb.ValueSlot_VALUE_SLOT_UNKNOWN,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION,
)
assert.Equal(t, uint64(1<<0), s.val)
assert.True(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_UNKNOWN, orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
assert.True(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_UNKNOWN, orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION))
})
t.Run("out_of_bounds_panics", func(t *testing.T) {
t.Parallel()
assert.PanicLike(t, func() {
SlotSet{}.Set(orchestratorpb.ValueSlot(-1))
}, "slot out of range")
assert.PanicLike(t, func() {
SlotSet{}.Set(orchestratorpb.ValueSlot_VALUE_SLOT_ALL + 1)
}, "slot out of range")
assert.PanicLike(t, func() {
SlotSet{}.Unset(orchestratorpb.ValueSlot_VALUE_SLOT_ALL + 1)
}, "slot out of range")
assert.PanicLike(t, func() {
SlotSet{}.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_ALL + 1)
}, "slot out of range")
assert.PanicLike(t, func() {
SlotSet{}.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_ALL + 1)
}, "slot out of range")
})
t.Run("slot_all", func(t *testing.T) {
t.Parallel()
s := SlotSet{}.Set(orchestratorpb.ValueSlot_VALUE_SLOT_ALL)
assert.Equal(t, slotsAll, s.val)
assert.True(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_ALL))
assert.True(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_ALL))
assert.True(t, s.HasAll(
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_EDIT_REASON_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_EDIT_OPTION,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_EDIT_RESULT_DATA,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_LEGACY_WORKNODE,
orchestratorpb.ValueSlot_VALUE_SLOT_ATTEMPT_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_ATTEMPT_PROGRESS_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_EDIT_REASON_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_EDIT_ATTEMPT_DETAIL,
))
s = s.Unset(orchestratorpb.ValueSlot_VALUE_SLOT_ALL)
assert.Equal(t, uint64(0), s.val)
assert.False(t, s.HasAll(orchestratorpb.ValueSlot_VALUE_SLOT_ALL))
assert.False(t, s.HasAny(orchestratorpb.ValueSlot_VALUE_SLOT_ALL))
})
t.Run("cross_language_invariance_vector", func(t *testing.T) {
t.Parallel()
s := SlotSet{}.Set(
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA,
orchestratorpb.ValueSlot_VALUE_SLOT_ATTEMPT_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_ATTEMPT_PROGRESS_DETAIL,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_EDIT_ATTEMPT_DETAIL,
orchestratorpb.ValueSlot(64),
)
assert.Equal(t, uint64(0x8000000000000583), s.val)
})
t.Run("formatting", func(t *testing.T) {
t.Parallel()
s := SlotSet{}.Set(orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION, orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS)
assert.Equal(t, "value.SlotSet{CHECK_OPTION, STAGE_ARGS}", s.String())
})
t.Run("round_trip", func(t *testing.T) {
t.Parallel()
s1 := SlotSet{}.Set(
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_OPTION,
orchestratorpb.ValueSlot_VALUE_SLOT_CHECK_RESULT_DATA,
orchestratorpb.ValueSlot_VALUE_SLOT_STAGE_ARGS,
)
slots := slices.Collect(s1.Range())
s2 := SlotSet{}.Set(slots...)
assert.Equal(t, s1.val, s2.val)
})
}