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/flamegraph | |
| 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/flamegraph')
| -rw-r--r-- | internal/flamegraph/iordata_test.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/internal/flamegraph/iordata_test.go b/internal/flamegraph/iordata_test.go index 9957f9e..f499e5f 100644 --- a/internal/flamegraph/iordata_test.go +++ b/internal/flamegraph/iordata_test.go @@ -1,6 +1,7 @@ package flamegraph import ( + "bytes" "ior/internal/types" "syscall" "testing" @@ -109,6 +110,161 @@ func TestMerge(t *testing.T) { // }) } +func TestStringByNameUnknownField(t *testing.T) { + ir := IterRecord{ + Path: "/tmp/test", + TraceID: types.SYS_ENTER_OPENAT, + Comm: "testComm", + Pid: 1234, + Tid: 5678, + Flags: flagsType(syscall.O_RDONLY), + Cnt: Counter{Count: 1}, + } + + _, err := ir.StringByName("nonexistent") + if err == nil { + t.Error("Expected error for unknown field name, got nil") + } +} + +func TestStringByNameValidFields(t *testing.T) { + ir := IterRecord{ + Path: "/tmp/test", + TraceID: types.SYS_ENTER_OPENAT, + Comm: "testComm", + Pid: 1234, + Tid: 5678, + Flags: flagsType(syscall.O_RDONLY), + Cnt: Counter{Count: 1}, + } + + validFields := []string{"path", "comm", "tracepoint", "pid", "tid", "flags"} + for _, name := range validFields { + t.Run(name, func(t *testing.T) { + val, err := ir.StringByName(name) + if err != nil { + t.Errorf("Expected no error for field %q, got %v", name, err) + } + if val == "" { + t.Errorf("Expected non-empty string for field %q", name) + } + }) + } +} + +func TestCounterValueByNamePanic(t *testing.T) { + c := Counter{Count: 1, Duration: 100, DurationToPrev: 10, Bytes: 64} + + defer func() { + if r := recover(); r == nil { + t.Error("Expected panic for unknown counter name, got none") + } + }() + + c.ValueByName("nonexistent") +} + +func TestMergeEmpty(t *testing.T) { + traceId := types.SYS_ENTER_OPENAT + roFlag := flagsType(syscall.O_RDONLY) + + iod := iorData{paths: pathMap{ + "path1": {traceId: {"comm1": {100: {1000: {roFlag: Counter{ + Count: 10, + Duration: 1000, + DurationToPrev: 100, + Bytes: 64, + }}}}}}, + }} + + empty := newIorData() + merged := iod.merge(empty) + + if len(merged.paths) != 1 { + t.Errorf("Expected 1 path, got %d", len(merged.paths)) + } + cnt := merged.paths["path1"][traceId]["comm1"][100][1000][roFlag] + if cnt.Count != 10 || cnt.Duration != 1000 || cnt.DurationToPrev != 100 || cnt.Bytes != 64 { + t.Errorf("Expected original counter preserved, got %v", cnt) + } +} + +func TestAddZeroCounter(t *testing.T) { + iod := newIorData() + path := pathType("testPath") + traceId := types.SYS_ENTER_OPENAT + comm := commType("testComm") + pid := pidType(1234) + tid := tidType(5678) + flags := flagsType(syscall.O_RDONLY) + zero := Counter{} + + iod.add(path, traceId, comm, pid, tid, flags, zero) + + cnt, ok := iod.paths[path][traceId][comm][pid][tid][flags] + if !ok { + t.Fatal("Expected entry to exist for zero counter") + } + if cnt != zero { + t.Errorf("Expected zero counter %v, got %v", zero, cnt) + } +} + +func TestSerializeDeserializeRoundTrip(t *testing.T) { + traceId := types.SYS_ENTER_OPENAT + rdwrFlag := flagsType(syscall.O_RDWR) + roFlag := flagsType(syscall.O_RDONLY) + + original := iorData{paths: pathMap{ + "path1": {traceId: {"comm1": {100: {1000: {rdwrFlag: Counter{ + Count: 10, + Duration: 1000, + DurationToPrev: 100, + Bytes: 64, + }}}}}}, + "path2": {traceId: {"comm2": {200: {2000: {roFlag: Counter{ + Count: 20, + Duration: 2000, + DurationToPrev: 200, + Bytes: 128, + }}}}}}, + }} + + data, err := original.serialize() + if err != nil { + t.Fatalf("serialize failed: %v", err) + } + + restored := newIorData() + if err := restored.deserialize(bytes.NewBuffer(data)); err != nil { + t.Fatalf("deserialize failed: %v", err) + } + + if len(restored.paths) != len(original.paths) { + t.Fatalf("Expected %d paths, got %d", len(original.paths), len(restored.paths)) + } + + cnt1 := restored.paths["path1"][traceId]["comm1"][100][1000][rdwrFlag] + if cnt1.Count != 10 || cnt1.Duration != 1000 || cnt1.DurationToPrev != 100 || cnt1.Bytes != 64 { + t.Errorf("path1 counter mismatch: %v", cnt1) + } + + cnt2 := restored.paths["path2"][traceId]["comm2"][200][2000][roFlag] + if cnt2.Count != 20 || cnt2.Duration != 2000 || cnt2.DurationToPrev != 200 || cnt2.Bytes != 128 { + t.Errorf("path2 counter mismatch: %v", cnt2) + } +} + +func TestDeserializeInvalidData(t *testing.T) { + iod := newIorData() + var buf bytes.Buffer + buf.WriteString("this is not valid gob data") + err := iod.deserialize(&buf) + if err == nil { + t.Error("Expected error when deserializing invalid data, got nil") + } +} + func bothArraysHaveSameElements(a, b []string) bool { if len(a) != len(b) { return false |
