diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-21 21:56:36 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-21 21:56:36 +0200 |
| commit | 311b827599251d8d68526293815e8d4dcba632c8 (patch) | |
| tree | 589d01f5653f966c3b2cc786911b8cc02a3237c9 /internal/generate | |
| parent | 36f216c757eea7db82cf04aeae592956199b9f76 (diff) | |
Add negative tests for all internal unit tests (task 348)
- internal/types: Fix StringValue panic with no null terminator,
add negative tests for serialization, Equals, and StringValue edge cases
- internal/file: Add negative tests for empty name, unknown flags,
SetFlags/AddFlags, Dup, empty OldnameNewname and Pathname
- internal/flamegraph: Add negative tests for StringByName unknown field,
Counter.ValueByName panic, merge empty, deserialize invalid data,
serialize/deserialize round-trip
- internal/generate/format: Add negative tests for empty input, ID errors,
malformed fields, empty declarations
- internal/generate/typesgo: Add negative tests for snakeToCamel edge cases,
unknown types, invalid member/define parsing, no-import case
- internal/generate/tracepointsgo: Add negative tests for malformed SEC,
no SEC lines
- internal/generate/codegen: Add negative tests for unknown event kind,
invalid syscall grouping, missing exit tracepoint
- internal/generate/classify: Add negative tests for empty external fields,
non-fd types
Amp-Thread-ID: https://ampcode.com/threads/T-019c81bf-3d5c-7216-b1b6-890db1374414
Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'internal/generate')
| -rw-r--r-- | internal/generate/classify_test.go | 29 | ||||
| -rw-r--r-- | internal/generate/codegen_test.go | 35 | ||||
| -rw-r--r-- | internal/generate/format_test.go | 40 | ||||
| -rw-r--r-- | internal/generate/tracepointsgo_test.go | 29 | ||||
| -rw-r--r-- | internal/generate/typesgo_test.go | 69 |
5 files changed, 202 insertions, 0 deletions
diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index 950e056..07c6027 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -341,6 +341,35 @@ func TestClassifySyscallPairIgnored(t *testing.T) { } } +func TestClassifyFormatNoExternalFields(t *testing.T) { + f := &Format{ + Name: "sys_enter_test", + ID: 999, + ExternalFields: nil, + } + r := ClassifyFormat(f) + if r.Kind != KindNone { + t.Errorf("ClassifyFormat with empty ExternalFields: got kind %d, want KindNone", r.Kind) + } +} + +func TestIsFdTypeNonMatch(t *testing.T) { + nonFdTypes := []string{ + "const char *", + "long", + "size_t", + "pid_t", + "umode_t", + "char *", + "void *", + } + for _, typ := range nonFdTypes { + if isFdType(typ) { + t.Errorf("isFdType(%q) = true, want false", typ) + } + } +} + func mustParseAll(t *testing.T, data string) []Format { t.Helper() formats, err := ParseFormats(strings.NewReader(data)) diff --git a/internal/generate/codegen_test.go b/internal/generate/codegen_test.go index 23ab7c1..6402214 100644 --- a/internal/generate/codegen_test.go +++ b/internal/generate/codegen_test.go @@ -285,6 +285,41 @@ func TestEnterReject(t *testing.T) { } } +func TestEventStructNameUnknown(t *testing.T) { + if got := eventStructName(TracepointKind(999)); got != "unknown_event" { + t.Errorf("eventStructName(999) = %q, want \"unknown_event\"", got) + } +} + +func TestEventTypeConstantUnknown(t *testing.T) { + if got := eventTypeConstant(TracepointKind(999), true); got != "ENTER_UNKNOWN_EVENT" { + t.Errorf("eventTypeConstant(999, true) = %q, want \"ENTER_UNKNOWN_EVENT\"", got) + } + if got := eventTypeConstant(TracepointKind(999), false); got != "EXIT_UNKNOWN_EVENT" { + t.Errorf("eventTypeConstant(999, false) = %q, want \"EXIT_UNKNOWN_EVENT\"", got) + } +} + +func TestGroupBySyscallInvalid(t *testing.T) { + formats := []Format{ + {Name: "tooshort", ID: 1}, + {Name: "also_short", ID: 2}, + } + output := GenerateTracepointsC(formats) + if strings.Contains(output, "SEC(") { + t.Error("formats with fewer than 3 name parts should not produce SEC handlers") + } +} + +func TestClassifySyscallNoExit(t *testing.T) { + formats := mustParseAll(t, FormatRead) + output := GenerateTracepointsC(formats) + requireContains(t, output, "Ignoring") + if strings.Contains(output, "SEC(") { + t.Error("syscall with only enter and no exit should be ignored") + } +} + func requireContains(t *testing.T, haystack, needle string) { t.Helper() if !strings.Contains(haystack, needle) { diff --git a/internal/generate/format_test.go b/internal/generate/format_test.go index f8f078b..a77ee2a 100644 --- a/internal/generate/format_test.go +++ b/internal/generate/format_test.go @@ -172,3 +172,43 @@ func TestParseFormatError(t *testing.T) { t.Error("expected error for field without name") } } + +func TestParseFormatEmptyInput(t *testing.T) { + formats, err := ParseFormats(strings.NewReader("")) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(formats) != 0 { + t.Errorf("expected 0 formats, got %d", len(formats)) + } +} + +func TestParseFormatIDWithoutName(t *testing.T) { + _, err := ParseFormats(strings.NewReader("ID: 123\n")) + if err == nil { + t.Error("expected error for ID without preceding name") + } +} + +func TestParseFormatInvalidID(t *testing.T) { + input := "name: sys_enter_test\nID: notanumber\n" + _, err := ParseFormats(strings.NewReader(input)) + if err == nil { + t.Error("expected error for non-numeric ID") + } +} + +func TestParseFieldNotEnoughParts(t *testing.T) { + input := "name: sys_enter_test\nID: 100\nfield:unsigned int fd; offset:16\n" + _, err := ParseFormats(strings.NewReader(input)) + if err == nil { + t.Error("expected error for field with fewer than 4 semicolons") + } +} + +func TestSplitDeclarationEmpty(t *testing.T) { + typePart, namePart := splitDeclaration("") + if typePart != "" || namePart != "" { + t.Errorf("splitDeclaration(\"\") = (%q, %q), want (\"\", \"\")", typePart, namePart) + } +} diff --git a/internal/generate/tracepointsgo_test.go b/internal/generate/tracepointsgo_test.go index d0f90db..cd24942 100644 --- a/internal/generate/tracepointsgo_test.go +++ b/internal/generate/tracepointsgo_test.go @@ -90,3 +90,32 @@ func TestExtractTracepointsPackageHeader(t *testing.T) { t.Errorf("unexpected header: %s", output[:60]) } } + +func TestExtractTracepointsMalformedSEC(t *testing.T) { + input := `SEC("tracepoint/not_matching_pattern") +int handle_something(struct trace_event_raw_sys_enter *ctx) { + return 0; +} +SEC("some/garbage") +` + output, err := ExtractTracepoints(strings.NewReader(input)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if strings.Contains(output, `"sys_`) { + t.Error("malformed SEC lines should not produce tracepoints") + } + requireContains(t, output, "var List = []string{") +} + +func TestExtractTracepointsNoSECLines(t *testing.T) { + input := "// just a comment\n/* another comment */\nint foo() { return 0; }\n" + output, err := ExtractTracepoints(strings.NewReader(input)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + requireContains(t, output, "var List = []string{") + if strings.Contains(output, `"sys_`) { + t.Error("input with no SEC lines should produce empty list") + } +} diff --git a/internal/generate/typesgo_test.go b/internal/generate/typesgo_test.go index f1085b5..89dafa8 100644 --- a/internal/generate/typesgo_test.go +++ b/internal/generate/typesgo_test.go @@ -255,3 +255,72 @@ func TestGenerateTypesGoPackageDecl(t *testing.T) { t.Errorf("unexpected package header: %s", output[:80]) } } + +func TestSnakeToCamelEmpty(t *testing.T) { + if got := snakeToCamel(""); got != "" { + t.Errorf("snakeToCamel(\"\") = %q, want \"\"", got) + } +} + +func TestSnakeToCamelLeadingUnderscore(t *testing.T) { + got := snakeToCamel("__u32") + if got != "U32" { + t.Errorf("snakeToCamel(\"__u32\") = %q, want \"U32\"", got) + } +} + +func TestCTypeToGoTypeUnknown(t *testing.T) { + if got := cTypeToGoType("some_custom_type"); got != "some_custom_type" { + t.Errorf("cTypeToGoType(\"some_custom_type\") = %q, want \"some_custom_type\"", got) + } +} + +func TestParseMemberInvalid(t *testing.T) { + tests := []string{ + "not a valid member line", + "too many words here that do not match", + "", + ";;;", + } + for _, input := range tests { + _, ok := parseMember(input) + if ok { + t.Errorf("parseMember(%q) returned ok=true, want false", input) + } + } +} + +func TestParseDefineInvalid(t *testing.T) { + tests := []string{ + "#define ONLY_NAME", + "#define", + "", + } + for _, input := range tests { + _, ok := parseDefine(input) + if ok { + t.Errorf("parseDefine(%q) returned ok=true, want false", input) + } + } +} + +func TestAddTypesImportsNoImport(t *testing.T) { + code := "package types\n\nconst FOO = 1\n" + got := AddTypesImports(code) + if got != code { + t.Errorf("AddTypesImports should not modify code without fmt/sync/binary usage, got:\n%s", got) + } +} + +func TestParseCTypesInputEmpty(t *testing.T) { + structs, constants, err := ParseCTypesInput(strings.NewReader("")) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(structs) != 0 { + t.Errorf("expected 0 structs, got %d", len(structs)) + } + if len(constants) != 0 { + t.Errorf("expected 0 constants, got %d", len(constants)) + } +} |
