github.com/tunabay/go-bitarray@v1.3.1/buffer_test.go (about)

     1  // Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
     2  // Use of this source code is governed by the MIT license that can be found in
     3  // the LICENSE file.
     4  
     5  package bitarray_test
     6  
     7  import (
     8  	"math/rand"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/tunabay/go-bitarray"
    14  )
    15  
    16  func TestNewBuffer(t *testing.T) {
    17  	for i := 0; i < 64*4+2; i++ {
    18  		buf := bitarray.NewBuffer(i)
    19  		buf.V()
    20  		if buf.Len() != i {
    21  			t.Errorf("invalid Len: got %d, want %d", buf.Len(), i)
    22  			t.Logf(" got: %s", buf.D())
    23  		}
    24  		if ba := buf.BitArray(); ba.OnesCount() != 0 {
    25  			t.Errorf("invalid BitArray: %s", ba)
    26  			t.Logf(" got: %s", buf.D())
    27  			t.Logf("  ba: %s", ba.D())
    28  		}
    29  	}
    30  	func() {
    31  		var buf *bitarray.Buffer
    32  		defer func() {
    33  			if recover() == nil {
    34  				t.Errorf("panic expected: got %s", buf.D())
    35  			}
    36  		}()
    37  		buf = bitarray.NewBuffer(-1)
    38  	}()
    39  }
    40  
    41  func TestNewBufferFromBitArray(t *testing.T) {
    42  	chk := func(got *bitarray.Buffer, bawant *bitarray.BitArray) {
    43  		got.V()
    44  		bagot := got.BitArray()
    45  		bagot.V()
    46  		if !bawant.Equal(bagot) {
    47  			t.Error("unexpected BitArray exporeted:")
    48  			t.Logf(" got: %s", got.String())
    49  			t.Logf(" got: %s", got.D())
    50  			t.Logf(" got: %#b", bagot)
    51  			t.Logf(" got: %s", bagot.D())
    52  			t.Logf("want: %#b", bawant)
    53  		}
    54  		gLen, wLen := got.Len(), bawant.Len()
    55  		if gLen != wLen {
    56  			t.Errorf("unexpected Len: got %d, want %d", gLen, wLen)
    57  		}
    58  	}
    59  	for i := 0; i < 64*4+2; i++ {
    60  		ba := bitarray.NewZeroFilled(i)
    61  		buf := bitarray.NewBufferFromBitArray(ba)
    62  		chk(buf, ba)
    63  
    64  		ba = bitarray.NewOneFilled(i)
    65  		buf = bitarray.NewBufferFromBitArray(ba)
    66  		chk(buf, ba)
    67  	}
    68  	tds := []string{
    69  		"1100-101",
    70  		"1100-1010",
    71  		"1100-1010 1",
    72  		"1100-1010 10",
    73  		"1100-1010 1010-1111 1111-0000 1010-111",
    74  		"1100-1010 1010-1111 1111-0000 1010-1111",
    75  		"1100-1010 1010-1111 1111-0000 1010-1111 1",
    76  		"1100-1010 1010-1111 1111-0000 1010-1111 11",
    77  	}
    78  	for _, td := range tds {
    79  		ba := bitarray.MustParse(td)
    80  		buf := bitarray.NewBufferFromBitArray(ba)
    81  		chk(buf, ba)
    82  	}
    83  
    84  	bufn := bitarray.NewBufferFromBitArray(nil)
    85  	switch {
    86  	case bufn == nil:
    87  		t.Errorf("unexpected nil buf.")
    88  	case !bufn.IsZero() || bufn.Len() != 0:
    89  		t.Errorf("unexpected buf: %s", bufn.D())
    90  	}
    91  }
    92  
    93  func TestNewBufferFromByteSlicePartial(t *testing.T) {
    94  	dat := []byte{0b_1111_0000, 0b_1010_0101, 0b_1100_0011, 0b_0101_1010}
    95  	chk := func(off, nBits int, wantS string) {
    96  		want := bitarray.MustParse(wantS)
    97  		buf := bitarray.NewBufferFromByteSlicePartial(dat, off, nBits)
    98  		buf.V()
    99  		if ba := buf.BitArray(); !ba.Equal(want) {
   100  			t.Error("unexpected buffer:")
   101  			t.Logf(" got: %# b", ba)
   102  			t.Logf("want: %# b", want)
   103  			t.Logf(" buf: %s", buf.D())
   104  		}
   105  	}
   106  	chk(0, 0, "")
   107  	chk(0, 1, "1")
   108  	chk(0, 4, "1111")
   109  	chk(0, 7, "1111-000")
   110  	chk(0, 8, "1111-0000")
   111  	chk(0, 9, "1111-0000 1")
   112  	chk(0, 15, "1111-0000 1010-010")
   113  	chk(0, 16, "1111-0000 1010-0101")
   114  	chk(0, 17, "1111-0000 1010-0101 1")
   115  	chk(0, 32, "1111-0000 1010-0101 1100-0011 0101-1010")
   116  	chk(1, 4, "111-0")
   117  	chk(2, 4, "11-00")
   118  	chk(3, 4, "1-000")
   119  	chk(4, 4, "0000")
   120  	chk(4, 6, "0000 10")
   121  	chk(5, 5, "000 10")
   122  	chk(6, 4, "00 10")
   123  	chk(7, 0, "")
   124  	chk(7, 1, "0")
   125  	chk(7, 2, "0 1")
   126  	chk(7, 4, "0 101")
   127  	chk(7, 7, "0 1010-01")
   128  	chk(7, 8, "0 1010-010")
   129  	chk(7, 9, "0 1010-0101")
   130  	chk(7, 10, "0 1010-0101 1")
   131  	chk(7, 15, "0 1010-0101 1100-00")
   132  	chk(7, 16, "0 1010-0101 1100-001")
   133  	chk(7, 17, "0 1010-0101 1100-0011")
   134  	chk(7, 18, "0 1010-0101 1100-0011 0")
   135  	chk(7, 24, "0 1010-0101 1100-0011 0101-101")
   136  	chk(7, 25, "0 1010-0101 1100-0011 0101-1010")
   137  	chk(8, 0, "")
   138  	chk(8, 1, "1")
   139  	chk(8, 4, "1010")
   140  	chk(8, 7, "1010-010")
   141  	chk(8, 8, "1010-0101")
   142  	chk(8, 9, "1010-0101 1")
   143  	chk(8, 15, "1010-0101 1100-001")
   144  	chk(8, 16, "1010-0101 1100-0011")
   145  	chk(8, 17, "1010-0101 1100-0011 0")
   146  	chk(31, 0, "")
   147  	chk(31, 1, "0")
   148  	chk(32, 0, "")
   149  	chkpanic := func(off, nBits int) {
   150  		var buf *bitarray.Buffer
   151  		defer func() {
   152  			if recover() == nil {
   153  				t.Errorf("panic expected: off=%d, nBits=%d", off, nBits)
   154  				t.Errorf("buf: %s", buf.D())
   155  			}
   156  		}()
   157  		buf = bitarray.NewBufferFromByteSlicePartial(dat, off, nBits)
   158  	}
   159  	chkpanic(-1, 4)
   160  	chkpanic(0, -1)
   161  	chkpanic(0, 33)
   162  	chkpanic(1, 32)
   163  	chkpanic(31, 2)
   164  	chkpanic(32, 1)
   165  	chkpanic(33, 0)
   166  	chkpanic(64, 4)
   167  }
   168  
   169  func TestBuffer_Len_edge(t *testing.T) {
   170  	var buf *bitarray.Buffer
   171  	if n := buf.Len(); n != 0 {
   172  		t.Errorf("unexpected nil.Len: got %d, want 0", n)
   173  	}
   174  	if !buf.IsZero() {
   175  		t.Errorf("unexpected nil.IsZero: got false, want true")
   176  	}
   177  	buf = &bitarray.Buffer{}
   178  	if n := buf.Len(); n != 0 {
   179  		t.Errorf("unexpected zerov.Len: got %d, want 0", n)
   180  	}
   181  	if !buf.IsZero() {
   182  		t.Errorf("unexpected zerov.IsZero: got false, want true")
   183  	}
   184  	// other normal cases are covered by TestNewBufferFromBitArray()
   185  }
   186  
   187  func TestBuffer_Clone(t *testing.T) {
   188  	chk := func(buf *bitarray.Buffer, want *bitarray.BitArray) {
   189  		t.Helper()
   190  		ba := buf.BitArray()
   191  		if !ba.Equal(want) {
   192  			t.Error("unexpected:")
   193  			t.Logf(" got: %#b", ba)
   194  			t.Logf("data: %s", buf.D())
   195  			t.Logf("want: %#b", want)
   196  		}
   197  	}
   198  	test := func(ba *bitarray.BitArray) {
   199  		buf := bitarray.NewBufferFromBitArray(ba)
   200  		buf.V()
   201  		buf2 := buf.Clone()
   202  		buf2.V()
   203  		chk(buf2, ba)
   204  		buf.PutBitArrayAt(0, bitarray.NewZeroFilled(ba.Len()))
   205  		chk(buf2, ba)
   206  		buf.PutBitArrayAt(0, bitarray.NewOneFilled(ba.Len()))
   207  		chk(buf2, ba)
   208  	}
   209  	for i := 0; i < 130; i++ {
   210  		ba := bitarray.NewZeroFilled(i).ZOptimize()
   211  		test(ba)
   212  		test(ba.ZExpand())
   213  		ba = bitarray.NewOneFilled(i)
   214  		test(ba)
   215  	}
   216  }
   217  
   218  // tests BitArray, Len, Clone, String
   219  func TestBuffer_rand(t *testing.T) {
   220  	const testIterations = 30000
   221  	rand.Seed(time.Now().UnixNano())
   222  	for i := 0; i < testIterations; i++ {
   223  		var nBits int
   224  		switch rand.Intn(10) {
   225  		case 0:
   226  			nBits = rand.Intn(66)
   227  		case 1:
   228  			nBits = 8*(1+rand.Intn(32)) - 1 + rand.Intn(3)
   229  		case 2:
   230  			nBits = 256 + rand.Intn(2048)
   231  		default:
   232  			nBits = rand.Intn(256)
   233  		}
   234  		ba := bitarray.PseudoRand(nBits, nil)
   235  		buf := bitarray.NewBufferFromBitArray(ba)
   236  		buf.V()
   237  		got := buf.BitArray()
   238  		got.V()
   239  		if !got.Equal(ba) {
   240  			t.Error("unexpected result:")
   241  			t.Logf(" got: %#b", got)
   242  			t.Logf(" got: %s", got.D())
   243  			t.Logf("want: %#b", ba)
   244  		}
   245  		buf2 := buf.Clone()
   246  		buf2.V()
   247  		got = buf2.BitArray()
   248  		if !got.Equal(ba) {
   249  			t.Error("unexpected result:")
   250  			t.Logf(" got: %#b", got)
   251  			t.Logf(" got: %s", got.D())
   252  			t.Logf("want: %#b", ba)
   253  		}
   254  		gotS := buf.String()
   255  		wantS := ba.String()
   256  		if gotS != wantS {
   257  			t.Error("unexpected result:")
   258  			t.Logf(" got: %s", gotS)
   259  			t.Logf("want: %s", wantS)
   260  			t.Logf("data: %s", buf.D())
   261  		}
   262  		if buf.Len() != ba.Len() {
   263  			t.Errorf("unexpected len: got %d, want %d", buf.Len(), ba.Len())
   264  		}
   265  	}
   266  }
   267  
   268  func TestBuffer_Resize_edge(t *testing.T) {
   269  	chk := func(gotBuf *bitarray.Buffer, wantS string) {
   270  		t.Helper()
   271  		gotBuf.V()
   272  		got := gotBuf.BitArray()
   273  		want := bitarray.MustParse(wantS)
   274  		if !got.Equal(want) {
   275  			t.Error("unexpected:")
   276  			t.Logf(" got: %#b", got)
   277  			t.Logf(" got: %s", got.D())
   278  			t.Logf("want: %#b", want)
   279  		}
   280  	}
   281  	var nilba *bitarray.BitArray
   282  	buf := bitarray.NewBufferFromBitArray(nilba)
   283  	buf.V()
   284  	buf.Resize(20, bitarray.AlignLeft)
   285  	buf.V()
   286  	buf.PutByteAt(4, 0xff)
   287  	chk(buf, "0000-1111 1111-0000 0000")
   288  
   289  	buf.Resize(18, bitarray.AlignRight)
   290  	buf.V()
   291  	buf.FillBitsAt(12, 2, 1)
   292  	chk(buf, "00-1111 1111-0011 0000")
   293  
   294  	buf.Resize(12, bitarray.AlignLeft)
   295  	chk(buf, "00-1111 1111-00")
   296  
   297  	buf.Resize(1, bitarray.AlignLeft)
   298  	chk(buf, "0")
   299  
   300  	buf.Resize(19, bitarray.AlignLeft)
   301  	chk(buf, "0000-0000 0000-0000 000")
   302  
   303  	buf.Resize(0, bitarray.AlignLeft)
   304  	chk(buf, "")
   305  
   306  	buf.Resize(15, bitarray.AlignLeft)
   307  	chk(buf, "0000-0000 0000-000")
   308  
   309  	// negative size should cause a panic
   310  	func() {
   311  		defer func() {
   312  			if recover() == nil {
   313  				t.Errorf("panic expected: got %s", buf.D())
   314  			}
   315  		}()
   316  		buf.Resize(-1, bitarray.AlignLeft)
   317  	}()
   318  }
   319  
   320  func TestBuffer_Resize_rand(t *testing.T) {
   321  	const testIterations = 50000
   322  	rand.Seed(time.Now().UnixNano())
   323  	rndLen := func() int {
   324  		switch rand.Intn(5) {
   325  		case 0:
   326  			return rand.Intn(66)
   327  		case 1:
   328  			return 8*(1+rand.Intn(32)) - 1 + rand.Intn(3)
   329  		case 2:
   330  			return 256 + rand.Intn(2048)
   331  		}
   332  		return rand.Intn(256)
   333  	}
   334  	rndAlign := func() bitarray.Alignment {
   335  		if rand.Intn(2) == 0 {
   336  			return bitarray.AlignLeft
   337  		}
   338  		return bitarray.AlignRight
   339  	}
   340  	for i := 0; i < testIterations/10; i++ {
   341  		nBits := rndLen()
   342  		ba := bitarray.PseudoRand(nBits, nil)
   343  		buf := bitarray.NewBufferFromBitArray(ba)
   344  		buf.V()
   345  		for j := 0; j < 10; j++ {
   346  			oldNBits := buf.Len()
   347  			oldS := buf.String()
   348  			oldD := buf.D()
   349  			newNBits := rndLen()
   350  			align := rndAlign()
   351  			newS := oldS
   352  			switch {
   353  			case align == bitarray.AlignLeft && newNBits < oldNBits:
   354  				newS = oldS[:newNBits]
   355  			case align == bitarray.AlignLeft && oldNBits < newNBits:
   356  				newS = oldS + strings.Repeat("0", newNBits-oldNBits)
   357  			case align == bitarray.AlignRight && newNBits < oldNBits:
   358  				newS = oldS[oldNBits-newNBits:]
   359  			case align == bitarray.AlignRight && oldNBits < newNBits:
   360  				newS = strings.Repeat("0", newNBits-oldNBits) + oldS
   361  			}
   362  
   363  			buf.Resize(newNBits, align)
   364  			buf.V()
   365  			if n := buf.Len(); n != newNBits {
   366  				t.Errorf("unexpected len: got %d, want %d", n, newNBits)
   367  			}
   368  			gotS := buf.String()
   369  			if gotS != newS {
   370  				t.Errorf("unexpected result: %d -> %d", oldNBits, newNBits)
   371  				t.Logf(" got: %s", gotS)
   372  				t.Logf("want: %s", newS)
   373  				t.Logf(" old: %s", oldS)
   374  				t.Logf(" old: %s", oldD)
   375  			}
   376  			// if i < 32 {
   377  			// 	t.Logf("%3d: %3d: %4d -> %4d:", i, j, oldNBits, newNBits)
   378  			// }
   379  		}
   380  	}
   381  }
   382  
   383  func TestBuffer_FillBitsAt(t *testing.T) {
   384  	chk := func(gotBuf *bitarray.Buffer, wantS string) {
   385  		t.Helper()
   386  		gotBuf.V()
   387  		got := gotBuf.BitArray()
   388  		want := bitarray.MustParse(wantS)
   389  		if !got.Equal(want) {
   390  			t.Error("unexpected:")
   391  			t.Logf(" got: %#b", got)
   392  			t.Logf(" got: %s", got.D())
   393  			t.Logf("want: %#b", want)
   394  		}
   395  	}
   396  	buf := bitarray.NewBuffer(20)
   397  	chk(buf, "0000-0000 0000-0000 0000")
   398  	buf.FillBitsAt(0, 10, 1)
   399  	chk(buf, "1111-1111 1100-0000 0000")
   400  	buf.FillBitsAt(4, 8, 0)
   401  	chk(buf, "1111-0000 0000-0000 0000")
   402  	buf.FillBitsAt(6, 8, 1)
   403  	chk(buf, "1111-0011 1111-1100 0000")
   404  	buf.FillBitsAt(12, 4, 1)
   405  	chk(buf, "1111-0011 1111-1111 0000")
   406  	buf.FillBitsAt(10, 6, 0)
   407  	chk(buf, "1111-0011 1100-0000 0000")
   408  	buf.FillBitsAt(2, 18, 1)
   409  	chk(buf, "1111-1111 1111-1111 1111")
   410  	buf.FillBitsAt(8, 8, 0)
   411  	chk(buf, "1111-1111 0000-0000 1111")
   412  	buf.FillBitsAt(0, 0, 0)
   413  	chk(buf, "1111-1111 0000-0000 1111")
   414  	buf.FillBitsAt(20, 0, 0)
   415  	chk(buf, "1111-1111 0000-0000 1111")
   416  
   417  	chkpanic := func(off, nBits int, bit byte) {
   418  		defer func() {
   419  			if recover() == nil {
   420  				t.Errorf("panic expected: off=%d, nBits=%d, bit=%d.", off, nBits, bit)
   421  			}
   422  		}()
   423  		buf.FillBitsAt(off, nBits, bit)
   424  	}
   425  	chkpanic(-1, 4, 1)
   426  	chkpanic(0, -1, 1)
   427  	chkpanic(16, 8, 1)
   428  	chkpanic(99, 8, 1)
   429  	chkpanic(0, 99, 1)
   430  }