summaryrefslogtreecommitdiff
path: root/internal/generate
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-21 21:56:36 +0200
committerPaul Buetow <paul@buetow.org>2026-02-21 21:56:36 +0200
commit311b827599251d8d68526293815e8d4dcba632c8 (patch)
tree589d01f5653f966c3b2cc786911b8cc02a3237c9 /internal/generate
parent36f216c757eea7db82cf04aeae592956199b9f76 (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.go29
-rw-r--r--internal/generate/codegen_test.go35
-rw-r--r--internal/generate/format_test.go40
-rw-r--r--internal/generate/tracepointsgo_test.go29
-rw-r--r--internal/generate/typesgo_test.go69
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))
+ }
+}