github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/strings_test.go (about)

     1  package btf
     2  
     3  import (
     4  	"bytes"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/go-quicktest/qt"
     9  )
    10  
    11  func TestStringTable(t *testing.T) {
    12  	const in = "\x00one\x00two\x00"
    13  	const splitIn = "three\x00four\x00"
    14  
    15  	st, err := readStringTable(strings.NewReader(in), nil)
    16  	if err != nil {
    17  		t.Fatal(err)
    18  	}
    19  
    20  	// Parse string table of split BTF
    21  	split, err := readStringTable(strings.NewReader(splitIn), st)
    22  	if err != nil {
    23  		t.Fatal(err)
    24  	}
    25  
    26  	testcases := []struct {
    27  		offset uint32
    28  		want   string
    29  	}{
    30  		{0, ""},
    31  		{1, "one"},
    32  		{5, "two"},
    33  		{9, "three"},
    34  		{15, "four"},
    35  	}
    36  
    37  	for _, tc := range testcases {
    38  		have, err := split.Lookup(tc.offset)
    39  		if err != nil {
    40  			t.Errorf("Offset %d: %s", tc.offset, err)
    41  			continue
    42  		}
    43  
    44  		if have != tc.want {
    45  			t.Errorf("Offset %d: want %s but have %s", tc.offset, tc.want, have)
    46  		}
    47  	}
    48  
    49  	if _, err := st.Lookup(2); err == nil {
    50  		t.Error("No error when using offset pointing into middle of string")
    51  	}
    52  
    53  	// Make sure we reject bogus tables
    54  	_, err = readStringTable(strings.NewReader("\x00one"), nil)
    55  	if err == nil {
    56  		t.Fatal("Accepted non-terminated string")
    57  	}
    58  
    59  	_, err = readStringTable(strings.NewReader("one\x00"), nil)
    60  	if err == nil {
    61  		t.Fatal("Accepted non-empty first item")
    62  	}
    63  }
    64  
    65  func TestStringTableBuilder(t *testing.T) {
    66  	stb := newStringTableBuilder(0)
    67  
    68  	_, err := readStringTable(bytes.NewReader(stb.AppendEncoded(nil)), nil)
    69  	qt.Assert(t, qt.IsNil(err), qt.Commentf("Can't parse string table"))
    70  
    71  	_, err = stb.Add("foo\x00bar")
    72  	qt.Assert(t, qt.IsNotNil(err))
    73  
    74  	empty, err := stb.Add("")
    75  	qt.Assert(t, qt.IsNil(err))
    76  	qt.Assert(t, qt.Equals(empty, 0), qt.Commentf("The empty string is not at index 0"))
    77  
    78  	foo1, _ := stb.Add("foo")
    79  	foo2, _ := stb.Add("foo")
    80  	qt.Assert(t, qt.Equals(foo1, foo2), qt.Commentf("Adding the same string returns different offsets"))
    81  
    82  	table := stb.AppendEncoded(nil)
    83  	if n := bytes.Count(table, []byte("foo")); n != 1 {
    84  		t.Fatalf("Marshalled string table contains foo %d times instead of once", n)
    85  	}
    86  
    87  	_, err = readStringTable(bytes.NewReader(table), nil)
    88  	qt.Assert(t, qt.IsNil(err), qt.Commentf("Can't parse string table"))
    89  }
    90  
    91  func BenchmarkStringTableZeroLookup(b *testing.B) {
    92  	strings := vmlinuxTestdataSpec(b).strings
    93  
    94  	b.ResetTimer()
    95  	for i := 0; i < b.N; i++ {
    96  		s, err := strings.Lookup(0)
    97  		if err != nil {
    98  			b.Fatal(err)
    99  		}
   100  		if s != "" {
   101  			b.Fatal("0 is not the empty string")
   102  		}
   103  	}
   104  }
   105  
   106  func newStringTable(strings ...string) *stringTable {
   107  	offsets := make([]uint32, len(strings))
   108  
   109  	var offset uint32
   110  	for i, str := range strings {
   111  		offsets[i] = offset
   112  		offset += uint32(len(str)) + 1 // account for NUL
   113  	}
   114  
   115  	return &stringTable{nil, offsets, 0, strings}
   116  }