Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion pkg/configio/valuefmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,15 @@ func YAMLToCodec(tipo, enumName string, in any) (any, error) {
if m, ok := in.(map[string]any); ok {
return m, nil
}
return nil, fmt.Errorf("YAMLToCodec: unsupported tipo %q (value type %T)", tipo, in)
// Reached when tipo isn't a primitive AND the YAML value isn't a
// nested map. The most common cause is a compound DATA written as
// a scalar by mistake (e.g. `RELE_K1: ECCITATO` instead of the
// nested `RELE_K1: {Logica: ECCITATO, ...}` shape). Surface that
// shape in the error so the next reader doesn't have to guess.
return nil, fmt.Errorf(
"YAMLToCodec: TIPO=%q with value type %T is not a primitive; "+
"if this is a compound, its YAML value must be a nested map of sub-field values",
tipo, in)
}

// decodeHexToRegs parses an even-byte hex string (with or without
Expand Down
10 changes: 9 additions & 1 deletion pkg/session/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,15 @@ func (s *Session) encodeForWrite(d *catalog.Data, value any) ([]uint16, error) {
if cls, ok := s.tpl.Classes[d.Tipo]; ok {
m, ok := value.(map[string]any)
if !ok {
return nil, fmt.Errorf("set %s: compound TIPO=%s needs map[string]any, got %T", d.Name, d.Tipo, value)
// The previous message leaked the Go-internal `map[string]any`
// type, which is unactionable from a CLI argv — there's no
// way to pass a literal Go map as a shell string. Point at
// the supported dotted-path syntax instead so the next user
// hitting this lands on the right escape route.
return nil, fmt.Errorf(
"set %s: this is a compound (TIPO=%s); set sub-fields with dotted-path, "+
"e.g. %s.<subfield>=<value> (see `mythy set --help`)",
d.Name, d.Tipo, d.Name)
}
return codec.EncodeCompound(m, cls, s.tpl.Enums, d.CompoundOverrides)
}
Expand Down
33 changes: 33 additions & 0 deletions pkg/session/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package session_test

import (
"context"
"strings"
"testing"

"github.com/gridsociety/mythy/pkg/transport"
Expand Down Expand Up @@ -46,6 +47,38 @@ func TestSetEnumByLabel(t *testing.T) {
}
}

func TestSetCompoundWithScalarValuePointsToDottedPath(t *testing.T) {
// Issue #22 follow-up: when a user does `mythy set RELE_K1=foo`
// against a compound DATA, the error must (a) NOT leak the Go-
// internal `map[string]any` type — that's unactionable from a CLI
// — and (b) point the user at the supported dotted-path syntax
// with a concrete example. Locks the new wording so a future
// refactor doesn't quietly drop the hint.
f := transport.NewFake()
s := mkSession(t, f)

err := s.Set(context.Background(), "TEST_SOGLIA", "ECCITATO")
if err == nil {
t.Fatal("expected error, got nil")
}
got := err.Error()
for _, want := range []string{
"TEST_SOGLIA", // names the offending DATA
"compound", // explains why
"SOGLIA_T", // names the TIPO
"dotted-path", // names the supported syntax
"TEST_SOGLIA.<subfield>=<value>", // shows the exact form
"mythy set --help", // points at the full docs
} {
if !strings.Contains(got, want) {
t.Errorf("error message missing %q\nfull: %s", want, got)
}
}
if strings.Contains(got, "map[string]any") {
t.Errorf("error message must not leak the Go-internal type:\n%s", got)
}
}

func TestSetCompoundHonoursCompoundOverrides(t *testing.T) {
// Issue #6: encoding a compound DATA must honour the per-instance
// CompoundOverrides parsed from nested <DATA> children. TEST_SOGLIA
Expand Down