mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
b3f7c2cb30
### Why are the changes in this PR needed? The DAP debugger currently truncates variable values to a hardcoded limit of 100 characters, with no way for callers to configure it. Long values cannot be inspected or copied whole from a debugger UI. ### What are the changes in this PR? - Add a new `SetMaxVariableLength` Debugger option (in both `v1/debug` and the top-level `debug` package) - A value of 0 disables truncation; the default stays 100 characters for backward compatibility - Plumb the limit through `variableManager` and `namedVar`, so it applies to top-level and nested (object/array/set) variables alike - Relax `truncatedString` to return the original string unchanged when the limit is <= 0 - Add `TestTruncatedString` and `TestVariableValueLengthLimit` covering the default limit, unlimited (0), negative, custom limits, and boundary cases ### Notes - `go build ./...` and `go test ./v1/debug/...` both pass - Default behavior is unchanged; the new option is opt-in - This PR was developed with AI assistance (Claude Code) ### Further comments Refs #8890 --------- Signed-off-by: summy wu <summy.wu81@gmail.com>
162 lines
4.1 KiB
Go
162 lines
4.1 KiB
Go
// Copyright 2026 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package debug
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/open-policy-agent/opa/v1/ast"
|
|
)
|
|
|
|
func TestTruncatedString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
s string
|
|
max int
|
|
expected string
|
|
}{
|
|
{
|
|
name: "no truncation when max is 0",
|
|
s: strings.Repeat("a", 200),
|
|
max: 0,
|
|
expected: strings.Repeat("a", 200),
|
|
},
|
|
{
|
|
name: "no truncation when max is negative",
|
|
s: strings.Repeat("a", 200),
|
|
max: -1,
|
|
expected: strings.Repeat("a", 200),
|
|
},
|
|
{
|
|
name: "no truncation when max is 1 (avoids negative slice)",
|
|
s: "abcdefghij",
|
|
max: 1,
|
|
expected: "abcdefghij",
|
|
},
|
|
{
|
|
name: "no truncation when max is 2",
|
|
s: "abcdefghij",
|
|
max: 2,
|
|
expected: "abcdefghij",
|
|
},
|
|
{
|
|
name: "no truncation when max is 3",
|
|
s: "abcdefghij",
|
|
max: 3,
|
|
expected: "abcdefghij",
|
|
},
|
|
{
|
|
name: "truncation at default limit",
|
|
s: strings.Repeat("a", 200),
|
|
max: 100,
|
|
expected: strings.Repeat("a", 98) + "...",
|
|
},
|
|
{
|
|
name: "no truncation when value is under limit",
|
|
s: strings.Repeat("a", 50),
|
|
max: 100,
|
|
expected: strings.Repeat("a", 50),
|
|
},
|
|
{
|
|
name: "no truncation when value equals limit",
|
|
s: strings.Repeat("a", 100),
|
|
max: 100,
|
|
expected: strings.Repeat("a", 100),
|
|
},
|
|
{
|
|
name: "truncation when value exceeds limit by one",
|
|
s: strings.Repeat("a", 101),
|
|
max: 100,
|
|
expected: strings.Repeat("a", 98) + "...",
|
|
},
|
|
{
|
|
name: "small truncation limit",
|
|
s: "abcdefghij",
|
|
max: 5,
|
|
expected: "abc...",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := truncatedString(tc.s, tc.max)
|
|
if got != tc.expected {
|
|
t.Errorf("truncatedString(%q, %d) = %q, want %q", tc.s, tc.max, got, tc.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVariableValueLengthLimit(t *testing.T) {
|
|
// A string value longer than the default 100-character limit.
|
|
// ast.String.String() renders strings with surrounding quotes, so the
|
|
// expected values below include those quote characters.
|
|
longValue := strings.Repeat("x", 150)
|
|
// A string value under the limit.
|
|
shortValue := strings.Repeat("y", 50)
|
|
tests := []struct {
|
|
name string
|
|
maxVariableLength int
|
|
expectedLong string
|
|
expectedShort string
|
|
}{
|
|
{
|
|
name: "default limit truncates long values",
|
|
maxVariableLength: 100,
|
|
expectedLong: `"` + strings.Repeat("x", 97) + "...",
|
|
expectedShort: `"` + shortValue + `"`,
|
|
},
|
|
{
|
|
name: "zero limit disables truncation",
|
|
maxVariableLength: 0,
|
|
expectedLong: `"` + longValue + `"`,
|
|
expectedShort: `"` + shortValue + `"`,
|
|
},
|
|
{
|
|
name: "negative limit disables truncation",
|
|
maxVariableLength: -1,
|
|
expectedLong: `"` + longValue + `"`,
|
|
expectedShort: `"` + shortValue + `"`,
|
|
},
|
|
{
|
|
name: "custom limit",
|
|
maxVariableLength: 120,
|
|
expectedLong: `"` + strings.Repeat("x", 117) + "...",
|
|
expectedShort: `"` + shortValue + `"`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
vm := newVariableManager(tc.maxVariableLength)
|
|
ref := vm.addVars(func() []namedVar {
|
|
return []namedVar{
|
|
{name: "long", value: ast.StringTerm(longValue).Value},
|
|
{name: "short", value: ast.StringTerm(shortValue).Value},
|
|
}
|
|
})
|
|
|
|
vars, err := vm.vars(ref)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
got := map[string]string{}
|
|
for _, v := range vars {
|
|
got[v.Name()] = v.Value()
|
|
}
|
|
|
|
if got["long"] != tc.expectedLong {
|
|
t.Errorf("long variable value = %q (len %d), want %q (len %d)",
|
|
got["long"], len(got["long"]), tc.expectedLong, len(tc.expectedLong))
|
|
}
|
|
if got["short"] != tc.expectedShort {
|
|
t.Errorf("short variable value = %q, want %q", got["short"], tc.expectedShort)
|
|
}
|
|
})
|
|
}
|
|
}
|