From 013ffc24b866209de01c1e79c53e9789007c992d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Jan 2026 17:37:03 +0000 Subject: [PATCH] Fix lint issues and improve test coverage for Unmarshaler interface - Apply De Morgan's law in keyNeedsQuoting to satisfy staticcheck QF1001 - Remove unused splitTableUnmarshaler type from test - Fix unused parameter lint warning in errorUnmarshaler873 - Add test for quoted keys that need special handling - Add test for error propagation from UnmarshalTOML - Update customTable873 parser to handle quoted keys properly Coverage improved: - handleKeyValuesUnmarshaler: 80.0% -> 93.3% - keyNeedsQuoting: 66.7% -> 83.3% - Overall main package: 97.2% -> 97.5% --- unmarshaler.go | 4 +-- unmarshaler_test.go | 59 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/unmarshaler.go b/unmarshaler.go index defdfec..7a70165 100644 --- a/unmarshaler.go +++ b/unmarshaler.go @@ -749,8 +749,8 @@ func keyNeedsQuoting(key []byte) bool { } for _, b := range key { // Bare keys can only contain A-Za-z0-9_- - if !((b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') || - (b >= '0' && b <= '9') || b == '_' || b == '-') { + if (b < 'A' || b > 'Z') && (b < 'a' || b > 'z') && + (b < '0' || b > '9') && b != '_' && b != '-' { return true } } diff --git a/unmarshaler_test.go b/unmarshaler_test.go index f9f696a..06544d4 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -4416,6 +4416,10 @@ func (c *customTable873) UnmarshalTOML(data []byte) error { continue } key := string(bytes.TrimSpace(line[:eqIdx])) + // Remove quotes from quoted keys + if len(key) >= 2 && key[0] == '"' && key[len(key)-1] == '"' { + key = key[1 : len(key)-1] + } valueBytes := bytes.TrimSpace(line[eqIdx+1:]) // Remove quotes from string values if len(valueBytes) >= 2 && valueBytes[0] == '"' && valueBytes[len(valueBytes)-1] == '"' { @@ -4689,11 +4693,6 @@ value = "two" // and [a.b] and [a.d] are defined with another table [x] in between, // A should receive content for both b and d, but not x. func TestIssue873_SplitTables(t *testing.T) { - // splitTableUnmarshaler collects sub-table names it sees - type splitTableUnmarshaler struct { - SubTables map[string]map[string]string - } - // For this test, we expect each sub-table to be handled separately // The parent doesn't receive the sub-tables directly - each sub-table // (b and d) gets its own call to handleKeyValues @@ -4753,3 +4752,53 @@ version = "1.0" expected := "name = \"example\"\nversion = \"1.0\"\n" assert.Equal(t, expected, string(cfg.Plugin)) } + +// Test keys that need quoting (contain special characters) +func TestIssue873_QuotedKeys(t *testing.T) { + type Config struct { + Section customTable873 `toml:"section"` + } + + doc := ` +[section] +"key with spaces" = "value1" +"key.with.dots" = "value2" +` + + var cfg Config + err := toml.NewDecoder(bytes.NewReader([]byte(doc))). + EnableUnmarshalerInterface(). + Decode(&cfg) + + assert.NoError(t, err) + assert.Equal(t, 2, len(cfg.Section.Keys)) + assert.Equal(t, "value1", cfg.Section.Values["key with spaces"]) + assert.Equal(t, "value2", cfg.Section.Values["key.with.dots"]) +} + +// errorUnmarshaler873 is used to test error propagation from UnmarshalTOML +type errorUnmarshaler873 struct{} + +func (e *errorUnmarshaler873) UnmarshalTOML([]byte) error { + return errors.New("intentional error") +} + +// Test error propagation from UnmarshalTOML +func TestIssue873_UnmarshalerError(t *testing.T) { + doc := ` +[section] +key = "value" +` + + type Config struct { + Section errorUnmarshaler873 `toml:"section"` + } + + var cfg Config + err := toml.NewDecoder(bytes.NewReader([]byte(doc))). + EnableUnmarshalerInterface(). + Decode(&cfg) + + assert.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "intentional error")) +}