feat(client-go): add WriteArrayElements default-fill helper and document semantics

Regenerate Go proto types from mxaccess_gateway.proto so MxSparseArray,
MxSparseElement, and MxValue_SparseArrayValue appear in the generated
package; add MxSparseArray/MxSparseElement type aliases to types.go;
add Session.WriteArrayElements and the unexported buildSparseArrayValue
builder; add three unit tests covering the sparse oneof structure,
empty-map case, and the round-trip through WriteArrayElements; update
README with default-fill reset semantics and auto-normalize note.
This commit is contained in:
Joseph Doherty
2026-06-18 03:01:55 -04:00
parent 0702551c25
commit b7f29f3048
5 changed files with 1442 additions and 524 deletions
@@ -666,3 +666,101 @@ func authorizationFromContext(ctx context.Context) string {
}
return values[0]
}
// ---------------------------------------------------------------------------
// WriteArrayElements / buildSparseArrayValue unit tests
// ---------------------------------------------------------------------------
func TestBuildSparseArrayValueSetsSparseOneof(t *testing.T) {
elements := map[uint32]*MxValue{
2: Int32Value(99),
0: Int32Value(10),
}
v := buildSparseArrayValue(DataTypeInteger, 5, elements)
sa, ok := v.Kind.(*pb.MxValue_SparseArrayValue)
if !ok {
t.Fatalf("Kind is %T, want *pb.MxValue_SparseArrayValue", v.Kind)
}
got := sa.SparseArrayValue
if got.GetElementDataType() != DataTypeInteger {
t.Errorf("ElementDataType = %v, want DataTypeInteger", got.GetElementDataType())
}
if got.GetTotalLength() != 5 {
t.Errorf("TotalLength = %d, want 5", got.GetTotalLength())
}
if len(got.GetElements()) != 2 {
t.Fatalf("len(Elements) = %d, want 2", len(got.GetElements()))
}
// Elements must be sorted by index (ascending).
if got.GetElements()[0].GetIndex() != 0 {
t.Errorf("Elements[0].Index = %d, want 0", got.GetElements()[0].GetIndex())
}
if got.GetElements()[0].GetValue().GetInt32Value() != 10 {
t.Errorf("Elements[0].Value = %v, want 10", got.GetElements()[0].GetValue())
}
if got.GetElements()[1].GetIndex() != 2 {
t.Errorf("Elements[1].Index = %d, want 2", got.GetElements()[1].GetIndex())
}
if got.GetElements()[1].GetValue().GetInt32Value() != 99 {
t.Errorf("Elements[1].Value = %v, want 99", got.GetElements()[1].GetValue())
}
}
func TestBuildSparseArrayValueEmptyMapProducesEmptyElements(t *testing.T) {
v := buildSparseArrayValue(DataTypeBoolean, 4, map[uint32]*MxValue{})
sa, ok := v.Kind.(*pb.MxValue_SparseArrayValue)
if !ok {
t.Fatalf("Kind is %T, want *pb.MxValue_SparseArrayValue", v.Kind)
}
if len(sa.SparseArrayValue.GetElements()) != 0 {
t.Errorf("len(Elements) = %d, want 0", len(sa.SparseArrayValue.GetElements()))
}
if sa.SparseArrayValue.GetTotalLength() != 4 {
t.Errorf("TotalLength = %d, want 4", sa.SparseArrayValue.GetTotalLength())
}
}
func TestWriteArrayElementsSendsWriteCommandWithSparseOneof(t *testing.T) {
fake := &fakeGatewayServer{
invokeReply: &pb.MxCommandReply{
SessionId: "session-1",
Kind: pb.MxCommandKind_MX_COMMAND_KIND_WRITE,
ProtocolStatus: &pb.ProtocolStatus{
Code: pb.ProtocolStatusCode_PROTOCOL_STATUS_CODE_OK,
},
},
}
client, cleanup := newBufconnClient(t, fake)
defer cleanup()
session := NewSessionForID(client, "session-1")
err := session.WriteArrayElements(
context.Background(),
1, 2,
DataTypeFloat,
10,
map[uint32]*MxValue{3: FloatValue(1.5)},
0,
)
if err != nil {
t.Fatalf("WriteArrayElements() error = %v", err)
}
cmd := fake.invokeRequest.GetCommand()
if cmd.GetKind() != pb.MxCommandKind_MX_COMMAND_KIND_WRITE {
t.Fatalf("command kind = %s, want WRITE", cmd.GetKind())
}
val := cmd.GetWrite().GetValue()
sa, ok := val.Kind.(*pb.MxValue_SparseArrayValue)
if !ok {
t.Fatalf("value kind is %T, want *pb.MxValue_SparseArrayValue", val.Kind)
}
if sa.SparseArrayValue.GetTotalLength() != 10 {
t.Errorf("TotalLength = %d, want 10", sa.SparseArrayValue.GetTotalLength())
}
if sa.SparseArrayValue.GetElementDataType() != DataTypeFloat {
t.Errorf("ElementDataType = %v, want DataTypeFloat", sa.SparseArrayValue.GetElementDataType())
}
}