github.com/tunabay/go-bitarray@v1.3.1/builder_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  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"math/rand"
    12  	"testing"
    13  	"testing/iotest"
    14  	"time"
    15  
    16  	"github.com/tunabay/go-bitarray"
    17  )
    18  
    19  func TestNewBuilder(t *testing.T) {
    20  	bb1 := bitarray.NewBuilder(
    21  		bitarray.NewZeroFilled(10),
    22  		nil,
    23  		bitarray.NewOneFilled(10),
    24  		bitarray.New(),
    25  		bitarray.MustParse("0101"),
    26  		bitarray.NewZeroFilled(10).ZExpand(),
    27  		bitarray.NewOneFilled(10),
    28  		nil,
    29  	)
    30  	got1 := bb1.BitArray()
    31  	got1.V()
    32  	want1 := bitarray.MustParse("0000000000 1111111111 0101 0000000000 1111111111")
    33  	if !got1.Equal(want1) {
    34  		t.Error("unexpected result:")
    35  		t.Logf(" got: %#b", got1)
    36  		t.Logf(" got: %s", got1.D())
    37  		t.Logf("want: %#b", want1)
    38  	}
    39  
    40  	bb2 := bitarray.NewBuilder()
    41  	got2 := bb2.BitArray()
    42  	got2.V()
    43  	if !got2.IsZero() {
    44  		t.Error("unexpected result: want zero")
    45  		t.Logf(" got: %#b", got1)
    46  		t.Logf(" got: %s", got1.D())
    47  	}
    48  }
    49  
    50  func TestBuilder_BitArray(t *testing.T) {
    51  	b1 := []byte{0b_1111_0000, 0b_1010_1010, 0b_0000_1111, 0b_1100_1100}
    52  	bb1 := bitarray.NewBuilder(
    53  		nil,
    54  		bitarray.NewZeroFilled(5),           // 00000
    55  		bitarray.NewOneFilled(5),            // 11111
    56  		bitarray.NewByRunLength(1, 2, 3, 4), // 0110001111
    57  	)
    58  	bb1.A(b1, 5, 0, false)   // (empty)
    59  	bb1.A(b1, 2, 5, false)   // 11000
    60  	bb1.A(b1, 22, 10, false) // 11 1100 1100
    61  	bb1.A(b1, 4, 4, true)    // 0000
    62  	got1 := bb1.BitArray()
    63  	got1.V()
    64  	want1 := bitarray.MustParse("00000 11111 0110001111 11000 11 1100 1100 0000")
    65  	if !got1.Equal(want1) {
    66  		t.Error("unexpected result:")
    67  		t.Logf(" got: %#b", got1)
    68  		t.Logf(" got: %s", got1.D())
    69  		t.Logf("want: %#b", want1)
    70  	}
    71  	if bb1.String() != want1.String() {
    72  		t.Error("unexpected result:")
    73  		t.Logf(" got: %s", bb1.String())
    74  		t.Logf("want: %s", want1.String())
    75  	}
    76  	if bb1.Len() != want1.Len() {
    77  		t.Errorf("unexpected Len: got %d, want %d", bb1.Len(), want1.Len())
    78  	}
    79  }
    80  
    81  func TestBuilder_String(t *testing.T) {
    82  	b1 := []byte{0b_1111_0000, 0b_1010_1010, 0b_0000_1111, 0b_1100_1100}
    83  	bb1 := bitarray.NewBuilder(
    84  		nil,
    85  		bitarray.NewZeroFilled(7),           // 0000000
    86  		bitarray.NewOneFilled(7),            // 1111111
    87  		bitarray.NewByRunLength(4, 3, 2, 1), // 0000111001
    88  	)
    89  	bb1.A(b1, 15, 0, false) // (empty)
    90  	bb1.A(b1, 6, 4, false)  // 0010
    91  	bb1.A(b1, 6, 14, false) // 00 10101010 0000
    92  	bb1.A(b1, 12, 8, false) // 10100000
    93  	bb1.A(b1, 16, 9, false) // 00001111 1
    94  	bb1.A(b1, 4, 4, true)   // 0000
    95  	got1 := bb1.String()
    96  	want1 := "000000011111110000111001001000101010100000101000000000111110000"
    97  	if got1 != want1 {
    98  		t.Error("unexpected result:")
    99  		t.Logf(" got: %s", got1)
   100  		t.Logf("want: %s", want1)
   101  	}
   102  	if bb1.Len() != len(want1) {
   103  		t.Errorf("unexpected Len: got %d, want %d", bb1.Len(), len(want1))
   104  	}
   105  }
   106  
   107  func TestBuilder_WriteByteBits_rand(t *testing.T) {
   108  	const (
   109  		testIterations = 1000
   110  		testAppends    = 30
   111  	)
   112  	var (
   113  		bb   bitarray.Builder
   114  		want string
   115  	)
   116  
   117  	appendB := func(n int) {
   118  		bits := make([]byte, n)
   119  		for i := 0; i < n; i++ {
   120  			bits[i] = byte(rand.Intn(2))
   121  			want += string([]byte{'0' + bits[i]})
   122  		}
   123  		bb.WriteByteBits(bits)
   124  	}
   125  
   126  	for i := 0; i < testIterations; i++ {
   127  		bb.Reset()
   128  		want = ""
   129  		for j := 0; j < testAppends; j++ {
   130  			appendB(rand.Intn(128))
   131  			gsd := bb.String()
   132  			gsa := bb.BitArray().String()
   133  			if gsd != want || gsa != want {
   134  				t.Errorf("unexpected result:")
   135  				t.Logf("  got(direct): %s", gsd)
   136  				t.Logf(" got(convert): %s", gsa)
   137  				t.Logf("         want: %s", want)
   138  			}
   139  		}
   140  		// t.Logf("pass: %s", bb.String())
   141  	}
   142  }
   143  
   144  func TestBuilder_WriteBitsFromBytes_rand(t *testing.T) {
   145  	const (
   146  		testIterations = 2000
   147  		testAppends    = 50
   148  	)
   149  	var (
   150  		bb   bitarray.Builder
   151  		want string
   152  	)
   153  	hist := make([]string, 0, 100)
   154  
   155  	logf := func(f string, p ...interface{}) {
   156  		hist = append(hist, fmt.Sprintf(f, p...))
   157  	}
   158  	appendB := func() {
   159  		off := rand.Intn(32)
   160  		nBits := rand.Intn(32)
   161  		logf("append: %d bits, off %d", nBits, off)
   162  		nBytes := (off + nBits + 7) >> 3
   163  		buf := make([]byte, nBytes)
   164  		for i := off; i < off+nBits; i++ {
   165  			b := byte(rand.Intn(2)) & 1
   166  			iby := i >> 3
   167  			ibi := i & 7
   168  			buf[iby] |= b << (7 - ibi)
   169  			want += string([]byte{'0' + b})
   170  		}
   171  		logf("append: %08b", buf)
   172  		bb.WriteBitsFromBytes(buf, off, nBits)
   173  	}
   174  
   175  	for i := 0; i < testIterations; i++ {
   176  		bb.Reset()
   177  		want = ""
   178  		hist = hist[:0]
   179  		for j := 0; j < testAppends; j++ {
   180  			appendB()
   181  			gsd := bb.String()
   182  			gsa := bb.BitArray().String()
   183  			if gsd != want || gsa != want {
   184  				t.Errorf("unexpected result:")
   185  				t.Logf("  got(direct): %s", gsd)
   186  				t.Logf(" got(convert): %s", gsa)
   187  				t.Logf("         want: %s", want)
   188  				t.Logf("history:")
   189  				for k, h := range hist {
   190  					t.Logf("#%3d: %s", k, h)
   191  				}
   192  				t.FailNow()
   193  			}
   194  		}
   195  		// t.Logf("pass: %s", bb.String())
   196  	}
   197  }
   198  
   199  func TestBuilder_Write(t *testing.T) {
   200  	buf := []byte{0xff, 0x00, 0xcc, 0x33, 0xaa, 0x55, 0xee, 0x77}
   201  	bb := bitarray.NewBuilder(bitarray.NewOneFilled(2))
   202  	wantS := "11"
   203  	add := func(off, n int) {
   204  		sb := buf[off : off+n]
   205  		for _, b := range sb {
   206  			wantS += fmt.Sprintf("%08b", b)
   207  		}
   208  		wn, err := bb.Write(sb)
   209  		if wn != n || err != nil {
   210  			t.Errorf("Write: n=%d, want=%d, err=%s", wn, n, err)
   211  		}
   212  	}
   213  	add(3, 0)
   214  	add(0, 3)
   215  	add(0, 8)
   216  	add(1, 6)
   217  	add(7, 1)
   218  	add(5, 2)
   219  
   220  	if gotS := bb.String(); gotS != wantS {
   221  		t.Error("unexpected result:")
   222  		t.Logf(" got: %s", gotS)
   223  		t.Logf("want: %s", wantS)
   224  	}
   225  	if bb.Len() != len(wantS) {
   226  		t.Errorf("unexpected result: got %d, want %d", bb.Len(), len(wantS))
   227  	}
   228  	gotB := bb.BitArray()
   229  	gotB.V()
   230  	wantB := bitarray.MustParse(wantS)
   231  	if !gotB.Equal(wantB) {
   232  		t.Error("unexpected result:")
   233  		t.Logf(" got: %#b", gotB)
   234  		t.Logf(" got: %s", gotB.D())
   235  		t.Logf("want: %#b", wantB)
   236  	}
   237  }
   238  
   239  func TestBuilder_WriteByte_zero(t *testing.T) {
   240  	const nBytes = 123
   241  	nBits := nBytes << 3
   242  
   243  	bb := bitarray.NewBuilder()
   244  	for i := 0; i < nBytes; i++ {
   245  		if err := bb.WriteByte(0); err != nil {
   246  			t.Fatalf("WriteByte: %s", err)
   247  		}
   248  	}
   249  	wantB := bitarray.NewZeroFilled(nBits)
   250  	wantS := wantB.String()
   251  	if n := bb.Len(); n != nBits {
   252  		t.Errorf("unexpeted Len: got %d, want %d", n, nBits)
   253  	}
   254  	if gotS := bb.String(); gotS != wantS {
   255  		t.Error("unexpected result:")
   256  		t.Logf(" got: %s", gotS)
   257  		t.Logf("want: %s", wantS)
   258  	}
   259  	gotB := bb.BitArray()
   260  	gotB.V()
   261  	if !gotB.Equal(wantB) {
   262  		t.Error("unexpected result:")
   263  		t.Logf(" got: %#b", gotB)
   264  		t.Logf(" got: %s", gotB.D())
   265  		t.Logf("want: %#b", wantB)
   266  	}
   267  }
   268  
   269  func TestBuilder_WriteByte_rand(t *testing.T) {
   270  	const testIterations = 10000
   271  	rand.Seed(time.Now().UnixNano())
   272  	for i := 0; i < testIterations; i++ {
   273  		bb := bitarray.NewBuilder()
   274  		wantS := ""
   275  		maxAdds := 16
   276  		if rand.Intn(5) == 0 {
   277  			maxAdds = 256
   278  		}
   279  		nadds := rand.Intn(maxAdds)
   280  		for j := 0; j < nadds; j++ {
   281  			if rand.Intn(5) == 0 {
   282  				nBits := 1 + rand.Intn(7)
   283  				for k := 0; k < nBits; k++ {
   284  					bit := byte(rand.Intn(2))
   285  					if err := bb.WriteBit(bit); err != nil {
   286  						t.Fatalf("WriteBit: %s", err)
   287  					}
   288  					wantS += fmt.Sprintf("%b", bit)
   289  				}
   290  				continue
   291  			}
   292  			b := byte(rand.Intn(0x100))
   293  			if err := bb.WriteByte(b); err != nil {
   294  				t.Fatalf("WriteByte: %s", err)
   295  			}
   296  			wantS += fmt.Sprintf("%08b", b)
   297  		}
   298  		if gotS := bb.String(); gotS != wantS {
   299  			t.Error("unexpected result:")
   300  			t.Logf(" got: %s", gotS)
   301  			t.Logf("want: %s", wantS)
   302  		}
   303  		if bb.Len() != len(wantS) {
   304  			t.Errorf("unexpected len: got %d, want %d", bb.Len(), len(wantS))
   305  		}
   306  		gotB := bb.BitArray()
   307  		gotB.V()
   308  		wantB := bitarray.MustParse(wantS)
   309  		if !gotB.Equal(wantB) {
   310  			t.Error("unexpected result:")
   311  			t.Logf(" got: %#b", gotB)
   312  			t.Logf(" got: %s", gotB.D())
   313  			t.Logf("want: %#b", wantB)
   314  		}
   315  		// if i < 32 {
   316  		// 	t.Logf("pass: %#b", gotB)
   317  		// }
   318  	}
   319  }
   320  
   321  func TestBuilder_ReadFrom(t *testing.T) {
   322  	b := []byte{0b_1111_1010, 0b_0000_0101, 0b_1110_0111, 0b_1100_0011}
   323  	r := iotest.OneByteReader(bytes.NewBuffer(b))
   324  
   325  	bb := bitarray.NewBuilder(bitarray.NewZeroFilled(3))
   326  	rn, err := bb.ReadFrom(r)
   327  	if err != nil {
   328  		t.Errorf("ReadFrom: %s", err)
   329  	}
   330  	if rn != 4 {
   331  		t.Errorf("unexpected length read: got %d, want 4", rn)
   332  	}
   333  	bb.WriteByteBits([]byte{0, 1})
   334  
   335  	gotS := bb.String()
   336  	gotB := bb.BitArray()
   337  	gotB.V()
   338  
   339  	wantS := "0001111101000000101111001111100001101"
   340  	wantB := bitarray.MustParse(wantS)
   341  
   342  	if gotS != wantS {
   343  		t.Error("unexpected result:")
   344  		t.Logf(" got: %s", gotS)
   345  		t.Logf("want: %s", wantS)
   346  	}
   347  	if bb.Len() != len(wantS) {
   348  		t.Errorf("unexpected len: got %d, want %d", bb.Len(), len(wantS))
   349  	}
   350  	if !gotB.Equal(wantB) {
   351  		t.Error("unexpected result:")
   352  		t.Logf(" got: %#b", gotB)
   353  		t.Logf(" got: %s", gotB.D())
   354  		t.Logf("want: %#b", wantB)
   355  	}
   356  }
   357  
   358  func TestBuilder_ReadFrom_error(t *testing.T) {
   359  	myErr := errors.New("test")
   360  	r := iotest.ErrReader(myErr)
   361  
   362  	bb := bitarray.NewBuilder(bitarray.NewZeroFilled(100))
   363  	rn, err := bb.ReadFrom(r)
   364  	if err != nil {
   365  		if !errors.Is(err, myErr) {
   366  			t.Errorf("ReadFrom: unexpected error: %s", err)
   367  		}
   368  	} else {
   369  		t.Errorf("ReadFrom: expected error, but no error.")
   370  	}
   371  	if rn != 0 {
   372  		t.Errorf("unexpected length read: got %d, want 0", rn)
   373  	}
   374  }
   375  
   376  func TestBuilder_WriteBitArray(t *testing.T) {
   377  	bas := []*bitarray.BitArray{
   378  		nil, // overwritten
   379  		nil,
   380  		bitarray.New(),
   381  		bitarray.MustParse("1111-00"),
   382  		bitarray.NewZeroFilled(200),
   383  		bitarray.NewZeroFilled(200).ZExpand(),
   384  	}
   385  	for i, ba := range bas {
   386  		bb := bitarray.NewBuilder()
   387  		var wn int
   388  		var err error
   389  		if i == 0 {
   390  			wn, err = bb.WriteBitArray(nil) // untyped
   391  		} else {
   392  			wn, err = bb.WriteBitArray(ba)
   393  		}
   394  		if wn != ba.Len() {
   395  			t.Errorf("unexpected length: got %d, want %d", wn, ba.Len())
   396  		}
   397  		if err != nil {
   398  			t.Errorf("WriteBitArray: %s", err)
   399  		}
   400  		if bb.Len() != ba.Len() {
   401  			t.Errorf("unexpected length: got %d, want %d", bb.Len(), ba.Len())
   402  		}
   403  		wantS := ""
   404  		if ba != nil {
   405  			wantS = ba.String()
   406  		}
   407  		if gotS := bb.String(); gotS != wantS {
   408  			t.Error("unexpected result:")
   409  			t.Logf(" got: %s", gotS)
   410  			t.Logf("want: %s", wantS)
   411  		}
   412  		gotB := bb.BitArray()
   413  		gotB.V()
   414  		if !gotB.Equal(ba) {
   415  			t.Error("unexpected result:")
   416  			t.Logf(" got: %#b", gotB)
   417  			t.Logf(" got: %s", gotB.D())
   418  			t.Logf("want: %#b", ba)
   419  		}
   420  	}
   421  }
   422  
   423  func TestBuilder_WriteBitArray_multi(t *testing.T) {
   424  	var nilba *bitarray.BitArray
   425  	bas := []bitarray.BitArrayer{
   426  		bitarray.New(),
   427  		bitarray.NewZeroFilled(30).ZOptimize(),
   428  		bitarray.NewByRunLength(0, 7, 5, 3), // 111111100000111
   429  		bitarray.NewZeroFilled(20).ZExpand(),
   430  		bitarray.NewOneFilled(10).ZExpand(),
   431  		nilba,
   432  		bitarray.MustParse("0101-1111 1010-0111"),
   433  		bitarray.MustParse("0"),
   434  	}
   435  
   436  	bb := bitarray.NewBuilder()
   437  	for _, bai := range bas {
   438  		var nBits int
   439  		if bai != nil {
   440  			ba := bai.BitArray()
   441  			nBits = ba.Len()
   442  		}
   443  		wn, err := bb.WriteBitArray(bai)
   444  		if err != nil {
   445  			t.Errorf("WriteBitArray: %s", err)
   446  		}
   447  		if wn != nBits {
   448  			t.Errorf("WriteBitArray: unexpected len: got %d, want %d", wn, nBits)
   449  		}
   450  	}
   451  
   452  	gotS := bb.String()
   453  	wantS := "000000000000000000000000000000" + "111111100000111" +
   454  		"00000000000000000000" + "1111111111" +
   455  		"01011111" + "10100111" + "0"
   456  	if gotS != wantS {
   457  		t.Error("unexpected result:")
   458  		t.Logf(" got: %s", gotS)
   459  		t.Logf("want: %s", wantS)
   460  	}
   461  	if bb.Len() != len(wantS) {
   462  		t.Errorf("unexpected result: got %d, want %d", bb.Len(), len(wantS))
   463  	}
   464  
   465  	gotB := bb.BitArray()
   466  	gotB.V()
   467  	wantB := bitarray.MustParse(wantS)
   468  	if !gotB.Equal(wantB) {
   469  		t.Error("unexpected result:")
   470  		t.Logf(" got: %#b", gotB)
   471  		t.Logf(" got: %s", gotB.D())
   472  		t.Logf("want: %#b", wantB)
   473  	}
   474  }
   475  
   476  func TestBuilder_WriteBits(t *testing.T) {
   477  	srcBA := bitarray.MustParse("1111-0000 1100-0011").Repeat(10)
   478  	srcBuf := bitarray.NewBufferFromBitArray(srcBA)
   479  	wantS := ""
   480  	bb := bitarray.NewBuilder()
   481  
   482  	add := func(buf *bitarray.Buffer) {
   483  		t.Helper()
   484  		wantS += buf.String()
   485  		n, err := bb.WriteBits(buf)
   486  		if err != nil {
   487  			t.Fatalf("unexpected error: %v", err)
   488  		}
   489  		if n != buf.Len() {
   490  			t.Fatalf("unexpected n: got %d, want %d", n, buf.Len())
   491  		}
   492  		if got, want := bb.BitArray(), bitarray.MustParse(wantS); !got.Equal(want) {
   493  			t.Errorf("unexpected result:")
   494  			t.Logf(" got: %#b", got)
   495  			t.Logf("want: %#b", want)
   496  		}
   497  	}
   498  	for i := 0; i < 35; i++ {
   499  		for j := 0; j < 35; j++ {
   500  			add(srcBuf.Slice(i, i+j))
   501  		}
   502  	}
   503  	srcBuf.FillBits(0)
   504  
   505  	if got, want := bb.BitArray(), bitarray.MustParse(wantS); !got.Equal(want) {
   506  		t.Errorf("unexpected result:")
   507  		t.Logf(" got: %#b", got)
   508  		t.Logf("want: %#b", want)
   509  	}
   510  }