github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/internal/unsafeheader/unsafeheader_test.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package unsafeheader
     6  
     7  import (
     8  	"bytes"
     9  	"reflect"
    10  	"testing"
    11  	"unsafe"
    12  )
    13  
    14  // TestTypeMatchesReflectType ensures that the name and layout of the
    15  // unsafeheader types matches the corresponding Header types in the reflect
    16  // package.
    17  func TestTypeMatchesReflectType(t *testing.T) {
    18  	t.Run("SliceHeader", func(t *testing.T) {
    19  		testHeaderMatchesReflect(t, SliceHeader{}, reflect.SliceHeader{})
    20  	})
    21  
    22  	t.Run("StringHeader", func(t *testing.T) {
    23  		testHeaderMatchesReflect(t, StringHeader{}, reflect.StringHeader{})
    24  	})
    25  }
    26  
    27  func testHeaderMatchesReflect(t *testing.T, header, reflectHeader any) {
    28  	h := reflect.TypeOf(header)
    29  	rh := reflect.TypeOf(reflectHeader)
    30  
    31  	for i := 0; i < h.NumField(); i++ {
    32  		f := h.Field(i)
    33  		rf, ok := rh.FieldByName(f.Name)
    34  		if !ok {
    35  			t.Errorf("Field %d of %v is named %s, but no such field exists in %v", i, h, f.Name, rh)
    36  			continue
    37  		}
    38  		if !typeCompatible(f.Type, rf.Type) {
    39  			t.Errorf("%v.%s has type %v, but %v.%s has type %v", h, f.Name, f.Type, rh, rf.Name, rf.Type)
    40  		}
    41  		if f.Offset != rf.Offset {
    42  			t.Errorf("%v.%s has offset %d, but %v.%s has offset %d", h, f.Name, f.Offset, rh, rf.Name, rf.Offset)
    43  		}
    44  	}
    45  
    46  	if h.NumField() != rh.NumField() {
    47  		t.Errorf("%v has %d fields, but %v has %d", h, h.NumField(), rh, rh.NumField())
    48  	}
    49  	if h.Align() != rh.Align() {
    50  		t.Errorf("%v has alignment %d, but %v has alignment %d", h, h.Align(), rh, rh.Align())
    51  	}
    52  }
    53  
    54  var (
    55  	unsafePointerType = reflect.TypeOf(unsafe.Pointer(nil))
    56  	uintptrType       = reflect.TypeOf(uintptr(0))
    57  )
    58  
    59  func typeCompatible(t, rt reflect.Type) bool {
    60  	return t == rt || (t == unsafePointerType && rt == uintptrType)
    61  }
    62  
    63  // TestWriteThroughHeader ensures that the headers in the unsafeheader package
    64  // can successfully mutate variables of the corresponding built-in types.
    65  //
    66  // This test is expected to fail under -race (which implicitly enables
    67  // -d=checkptr) if the runtime views the header types as incompatible with the
    68  // underlying built-in types.
    69  func TestWriteThroughHeader(t *testing.T) {
    70  	t.Run("SliceHeader", func(t *testing.T) {
    71  		s := []byte("Hello, checkptr!")[:5]
    72  
    73  		var alias []byte
    74  		hdr := (*SliceHeader)(unsafe.Pointer(&alias))
    75  		hdr.Data = unsafe.Pointer(&s[0])
    76  		hdr.Cap = cap(s)
    77  		hdr.Len = len(s)
    78  
    79  		if !bytes.Equal(alias, s) {
    80  			t.Errorf("alias of %T(%q) constructed via SliceHeader = %T(%q)", s, s, alias, alias)
    81  		}
    82  		if cap(alias) != cap(s) {
    83  			t.Errorf("alias of %T with cap %d has cap %d", s, cap(s), cap(alias))
    84  		}
    85  	})
    86  
    87  	t.Run("StringHeader", func(t *testing.T) {
    88  		s := "Hello, checkptr!"
    89  
    90  		var alias string
    91  		hdr := (*StringHeader)(unsafe.Pointer(&alias))
    92  		hdr.Data = (*StringHeader)(unsafe.Pointer(&s)).Data
    93  		hdr.Len = len(s)
    94  
    95  		if alias != s {
    96  			t.Errorf("alias of %q constructed via StringHeader = %q", s, alias)
    97  		}
    98  	})
    99  }