...

Source file src/go.mongodb.org/mongo-driver/bson/bsoncodec/codec_cache_test.go

Documentation: go.mongodb.org/mongo-driver/bson/bsoncodec

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package bsoncodec
     8  
     9  import (
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  // NB(charlie): the array size is a power of 2 because we use the remainder of
    17  // it (mod) in benchmarks and that is faster when the size is a power of 2.
    18  var codecCacheTestTypes = [16]reflect.Type{
    19  	reflect.TypeOf(uint8(0)),
    20  	reflect.TypeOf(uint16(0)),
    21  	reflect.TypeOf(uint32(0)),
    22  	reflect.TypeOf(uint64(0)),
    23  	reflect.TypeOf(uint(0)),
    24  	reflect.TypeOf(uintptr(0)),
    25  	reflect.TypeOf(int8(0)),
    26  	reflect.TypeOf(int16(0)),
    27  	reflect.TypeOf(int32(0)),
    28  	reflect.TypeOf(int64(0)),
    29  	reflect.TypeOf(int(0)),
    30  	reflect.TypeOf(float32(0)),
    31  	reflect.TypeOf(float64(0)),
    32  	reflect.TypeOf(true),
    33  	reflect.TypeOf(struct{ A int }{}),
    34  	reflect.TypeOf(map[int]int{}),
    35  }
    36  
    37  func TestTypeCache(t *testing.T) {
    38  	rt := reflect.TypeOf(int(0))
    39  	ec := new(typeEncoderCache)
    40  	dc := new(typeDecoderCache)
    41  
    42  	codec := new(fakeCodec)
    43  	ec.Store(rt, codec)
    44  	dc.Store(rt, codec)
    45  	if v, ok := ec.Load(rt); !ok || !reflect.DeepEqual(v, codec) {
    46  		t.Errorf("Load(%s) = %v, %t; want: %v, %t", rt, v, ok, codec, true)
    47  	}
    48  	if v, ok := dc.Load(rt); !ok || !reflect.DeepEqual(v, codec) {
    49  		t.Errorf("Load(%s) = %v, %t; want: %v, %t", rt, v, ok, codec, true)
    50  	}
    51  
    52  	// Make sure we overwrite the stored value with nil
    53  	ec.Store(rt, nil)
    54  	dc.Store(rt, nil)
    55  	if v, ok := ec.Load(rt); ok || v != nil {
    56  		t.Errorf("Load(%s) = %v, %t; want: %v, %t", rt, v, ok, nil, false)
    57  	}
    58  	if v, ok := dc.Load(rt); ok || v != nil {
    59  		t.Errorf("Load(%s) = %v, %t; want: %v, %t", rt, v, ok, nil, false)
    60  	}
    61  }
    62  
    63  func TestTypeCacheClone(t *testing.T) {
    64  	codec := new(fakeCodec)
    65  	ec1 := new(typeEncoderCache)
    66  	dc1 := new(typeDecoderCache)
    67  	for _, rt := range codecCacheTestTypes {
    68  		ec1.Store(rt, codec)
    69  		dc1.Store(rt, codec)
    70  	}
    71  	ec2 := ec1.Clone()
    72  	dc2 := dc1.Clone()
    73  	for _, rt := range codecCacheTestTypes {
    74  		if v, _ := ec2.Load(rt); !reflect.DeepEqual(v, codec) {
    75  			t.Errorf("Load(%s) = %#v; want: %#v", rt, v, codec)
    76  		}
    77  		if v, _ := dc2.Load(rt); !reflect.DeepEqual(v, codec) {
    78  			t.Errorf("Load(%s) = %#v; want: %#v", rt, v, codec)
    79  		}
    80  	}
    81  }
    82  
    83  func TestKindCacheArray(t *testing.T) {
    84  	// Check array bounds
    85  	var c kindEncoderCache
    86  	codec := new(fakeCodec)
    87  	c.Store(reflect.UnsafePointer, codec)   // valid
    88  	c.Store(reflect.UnsafePointer+1, codec) // ignored
    89  	if v, ok := c.Load(reflect.UnsafePointer); !ok || v != codec {
    90  		t.Errorf("Load(reflect.UnsafePointer) = %v, %t; want: %v, %t", v, ok, codec, true)
    91  	}
    92  	if v, ok := c.Load(reflect.UnsafePointer + 1); ok || v != nil {
    93  		t.Errorf("Load(reflect.UnsafePointer + 1) = %v, %t; want: %v, %t", v, ok, nil, false)
    94  	}
    95  
    96  	// Make sure that reflect.UnsafePointer is the last/largest reflect.Type.
    97  	//
    98  	// The String() method of invalid reflect.Type types are of the format
    99  	// "kind{NUMBER}".
   100  	for rt := reflect.UnsafePointer + 1; rt < reflect.UnsafePointer+16; rt++ {
   101  		s := rt.String()
   102  		if !strings.Contains(s, strconv.Itoa(int(rt))) {
   103  			t.Errorf("reflect.Type(%d) appears to be valid: %q", rt, s)
   104  		}
   105  	}
   106  }
   107  
   108  func TestKindCacheClone(t *testing.T) {
   109  	e1 := new(kindEncoderCache)
   110  	d1 := new(kindDecoderCache)
   111  	codec := new(fakeCodec)
   112  	for k := reflect.Invalid; k <= reflect.UnsafePointer; k++ {
   113  		e1.Store(k, codec)
   114  		d1.Store(k, codec)
   115  	}
   116  	e2 := e1.Clone()
   117  	for k := reflect.Invalid; k <= reflect.UnsafePointer; k++ {
   118  		v1, ok1 := e1.Load(k)
   119  		v2, ok2 := e2.Load(k)
   120  		if ok1 != ok2 || !reflect.DeepEqual(v1, v2) || v1 == nil || v2 == nil {
   121  			t.Errorf("Encoder(%s): %#v, %t != %#v, %t", k, v1, ok1, v2, ok2)
   122  		}
   123  	}
   124  	d2 := d1.Clone()
   125  	for k := reflect.Invalid; k <= reflect.UnsafePointer; k++ {
   126  		v1, ok1 := d1.Load(k)
   127  		v2, ok2 := d2.Load(k)
   128  		if ok1 != ok2 || !reflect.DeepEqual(v1, v2) || v1 == nil || v2 == nil {
   129  			t.Errorf("Decoder(%s): %#v, %t != %#v, %t", k, v1, ok1, v2, ok2)
   130  		}
   131  	}
   132  }
   133  
   134  func TestKindCacheEncoderNilEncoder(t *testing.T) {
   135  	t.Run("Encoder", func(t *testing.T) {
   136  		c := new(kindEncoderCache)
   137  		c.Store(reflect.Invalid, ValueEncoder(nil))
   138  		v, ok := c.Load(reflect.Invalid)
   139  		if v != nil || ok {
   140  			t.Errorf("Load of nil ValueEncoder should return: nil, false; got: %v, %t", v, ok)
   141  		}
   142  	})
   143  	t.Run("Decoder", func(t *testing.T) {
   144  		c := new(kindDecoderCache)
   145  		c.Store(reflect.Invalid, ValueDecoder(nil))
   146  		v, ok := c.Load(reflect.Invalid)
   147  		if v != nil || ok {
   148  			t.Errorf("Load of nil ValueDecoder should return: nil, false; got: %v, %t", v, ok)
   149  		}
   150  	})
   151  }
   152  
   153  func BenchmarkEncoderCacheLoad(b *testing.B) {
   154  	c := new(typeEncoderCache)
   155  	codec := new(fakeCodec)
   156  	typs := codecCacheTestTypes
   157  	for _, t := range typs {
   158  		c.Store(t, codec)
   159  	}
   160  	b.RunParallel(func(pb *testing.PB) {
   161  		for i := 0; pb.Next(); i++ {
   162  			c.Load(typs[i%len(typs)])
   163  		}
   164  	})
   165  }
   166  
   167  func BenchmarkEncoderCacheStore(b *testing.B) {
   168  	c := new(typeEncoderCache)
   169  	codec := new(fakeCodec)
   170  	b.RunParallel(func(pb *testing.PB) {
   171  		typs := codecCacheTestTypes
   172  		for i := 0; pb.Next(); i++ {
   173  			c.Store(typs[i%len(typs)], codec)
   174  		}
   175  	})
   176  }
   177  

View as plain text