github.com/tunabay/go-bitarray@v1.3.1/util_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  	"fmt"
    10  	"math/rand"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/tunabay/go-bitarray"
    16  )
    17  
    18  func TestCopyBitsB(t *testing.T) {
    19  	test := func(
    20  		dst, src []byte,
    21  		dstOff, srcOff, nBits int,
    22  		exp []byte,
    23  	) {
    24  		t.Helper()
    25  		org := make([]byte, len(dst))
    26  		copy(org, dst)
    27  		bitarray.CopyBitsB(dst, src, dstOff, srcOff, nBits)
    28  		if !bytes.Equal(dst, exp) {
    29  			t.Error("unexpected result:")
    30  			t.Logf("dstOff=%d, srcOff=%d, nBits=%d", dstOff, srcOff, nBits)
    31  			t.Logf(" dst: %08b", org)
    32  			t.Logf(" src: %08b", src)
    33  			t.Logf(" got: %08b", dst)
    34  			t.Logf("want: %08b", exp)
    35  			t.FailNow()
    36  		}
    37  	}
    38  
    39  	test(
    40  		[]byte{0b_0000_0000},
    41  		[]byte{0b_1110_0000},
    42  		0, 0, 3,
    43  		[]byte{0b_1110_0000},
    44  	)
    45  	test(
    46  		[]byte{0b_1111_1011},
    47  		[]byte{0b_0010_0000},
    48  		0, 0, 4,
    49  		[]byte{0b_0010_1011},
    50  	)
    51  	test(
    52  		[]byte{0b_1111_1111},
    53  		[]byte{0b_0001_0011},
    54  		0, 0, 5,
    55  		[]byte{0b_0001_0111},
    56  	)
    57  	test(
    58  		[]byte{0b_1111_1111, 0b_0000_1111},
    59  		[]byte{0b_0010_0000, 0b_1111_0000},
    60  		3, 0, 4,
    61  		[]byte{0b_1110_0101, 0b_0000_1111},
    62  	)
    63  
    64  	test(
    65  		[]byte{0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
    66  		[]byte{0b_0000_0000, 0b_0000_0000, 0b_0000_0000, 0b_0000_0000, 0b_0000_0000},
    67  		10, 10, 12,
    68  		[]byte{0b_1111_1111, 0b_1100_0000, 0b_0000_0011, 0b_1111_1111, 0b_1111_1111},
    69  	)
    70  	test(
    71  		[]byte{0b_0000_0000, 0b_0000_0000, 0b_0000_0000, 0b_0000_0000, 0b_0000_0000},
    72  		[]byte{0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
    73  		8, 8, 12,
    74  		[]byte{0b_0000_0000, 0b_1111_1111, 0b_1111_0000, 0b_0000_0000, 0b_0000_0000},
    75  	)
    76  	test(
    77  		[]byte{0b_1111_1010, 0b_0000_0000, 0b_0000_0000, 0b_0000_0000, 0b_0000_1111},
    78  		[]byte{0b_0000_0111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
    79  		11, 5, 22,
    80  		[]byte{0b_1111_1010, 0b_0001_1111, 0b_1111_1111, 0b_1111_1111, 0b_1000_1111},
    81  	)
    82  }
    83  
    84  func mkBitsStr(b []byte) string {
    85  	s := ""
    86  	for _, be := range b {
    87  		s += fmt.Sprintf("%08b", be)
    88  	}
    89  	return s
    90  }
    91  
    92  func mkRandBits() []byte {
    93  	b := make([]byte, 1+rand.Intn(8)) // len = 1..8
    94  	rand.Read(b)
    95  	return b
    96  }
    97  
    98  func dupBits(b []byte) []byte {
    99  	d := make([]byte, len(b))
   100  	copy(d, b)
   101  	return d
   102  }
   103  
   104  func sfmt(s string) string {
   105  	f := make([]string, (len(s)+7)>>3)
   106  	for i := 0; i < len(f); i++ {
   107  		f[i] = s[i<<3 : (i+1)<<3]
   108  	}
   109  	return fmt.Sprintf("[%s]", strings.Join(f, " "))
   110  }
   111  
   112  func TestCopyBitsB_rand(t *testing.T) {
   113  	const testIterations = 50000
   114  	rand.Seed(time.Now().UnixNano())
   115  	for i := 0; i < testIterations; i++ {
   116  		dstB, srcB := mkRandBits(), mkRandBits()
   117  		dstS, srcS := mkBitsStr(dstB), mkBitsStr(srcB)
   118  		orgB := dupBits(dstB)
   119  		orgS := mkBitsStr(orgB)
   120  
   121  		wid := len(dstS)
   122  		if len(srcS) < wid {
   123  			wid = len(srcS)
   124  		}
   125  		nBits := rand.Intn(wid) + 1
   126  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   127  		src0 := rand.Intn(len(srcS) - nBits + 1)
   128  
   129  		subpS := srcS[src0 : src0+nBits]
   130  		wantS := orgS[:dst0] + subpS + orgS[dst0+nBits:]
   131  		gotZF := bitarray.CopyBitsB(dstB, srcB, dst0, src0, nBits)
   132  		dstS = mkBitsStr(dstB)
   133  
   134  		if gotZF && strings.Contains(subpS, "1") {
   135  			t.Errorf("unexpected ZF: true for %q", subpS)
   136  		}
   137  		if dstS != wantS {
   138  			t.Errorf("unexpected result: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   139  		}
   140  		if t.Failed() {
   141  			t.Logf(" dst: %08b", orgB)
   142  			t.Logf(" src: %08b", srcB)
   143  			t.Logf(" got: %08b", dstB)
   144  			t.Logf("want: %s", sfmt(wantS))
   145  			t.FailNow()
   146  		}
   147  		// if i < 30 {
   148  		// 	t.Logf("pass: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   149  		// 	t.Logf(" dst: %08b", orgB)
   150  		// 	t.Logf(" src: %08b", srcB)
   151  		// 	t.Logf(" got: %08b", dstB)
   152  		// }
   153  	}
   154  }
   155  
   156  func TestClearBits(t *testing.T) {
   157  	test := func(
   158  		dst []byte,
   159  		off, nBits int,
   160  		exp []byte,
   161  	) {
   162  		t.Helper()
   163  		org := make([]byte, len(dst))
   164  		copy(org, dst)
   165  		bitarray.ClearBits(dst, off, nBits)
   166  		if !bytes.Equal(dst, exp) {
   167  			t.Error("unexpected result:")
   168  			t.Logf("off=%d, nBits=%d", off, nBits)
   169  			t.Logf(" dst: %08b", org)
   170  			t.Logf(" got: %08b", dst)
   171  			t.Logf("want: %08b", exp)
   172  			t.FailNow()
   173  		}
   174  	}
   175  
   176  	test(
   177  		[]byte{0b_1111_1111},
   178  		0, 1,
   179  		[]byte{0b_0111_1111},
   180  	)
   181  	test(
   182  		[]byte{0b_1111_1111},
   183  		0, 3,
   184  		[]byte{0b_0001_1111},
   185  	)
   186  	test(
   187  		[]byte{0b_1111_1111},
   188  		5, 2,
   189  		[]byte{0b_1111_1001},
   190  	)
   191  	test(
   192  		[]byte{0b_1111_1111},
   193  		7, 1,
   194  		[]byte{0b_1111_1110},
   195  	)
   196  	test(
   197  		[]byte{0b_1111_1111, 0b_1111_1111},
   198  		4, 3,
   199  		[]byte{0b_1111_0001, 0b_1111_1111},
   200  	)
   201  	test(
   202  		[]byte{0b_1111_1111, 0b_1111_1111},
   203  		5, 3,
   204  		[]byte{0b_1111_1000, 0b_1111_1111},
   205  	)
   206  	test(
   207  		[]byte{0b_1111_1111, 0b_1111_1111},
   208  		5, 4,
   209  		[]byte{0b_1111_1000, 0b_0111_1111},
   210  	)
   211  	test(
   212  		[]byte{0b_1111_1111, 0b_1111_1111},
   213  		7, 1,
   214  		[]byte{0b_1111_1110, 0b_1111_1111},
   215  	)
   216  
   217  	test(
   218  		[]byte{0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
   219  		8, 8,
   220  		[]byte{0b_1111_1111, 0b_0000_0000, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
   221  	)
   222  	test(
   223  		[]byte{0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111, 0b_1111_1111},
   224  		6, 21,
   225  		[]byte{0b_1111_1100, 0b_0000_0000, 0b_0000_0000, 0b_0001_1111, 0b_1111_1111},
   226  	)
   227  }
   228  
   229  func TestClearBits_rand(t *testing.T) {
   230  	const testIterations = 50000
   231  	rand.Seed(time.Now().UnixNano())
   232  	for i := 0; i < testIterations; i++ {
   233  		dstB := mkRandBits()
   234  		dstS := mkBitsStr(dstB)
   235  		orgB := dupBits(dstB)
   236  		orgS := mkBitsStr(orgB)
   237  
   238  		nBits := rand.Intn(len(dstS)) + 1
   239  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   240  
   241  		wantS := orgS[:dst0] + strings.Repeat("0", nBits) + orgS[dst0+nBits:]
   242  		bitarray.ClearBits(dstB, dst0, nBits)
   243  		dstS = mkBitsStr(dstB)
   244  
   245  		if dstS != wantS {
   246  			t.Errorf("unexpected result: off=%d, nBits=%d", dst0, nBits)
   247  			t.Logf(" dst: %08b", orgB)
   248  			t.Logf(" got: %08b", dstB)
   249  			t.Logf("want: %s", sfmt(wantS))
   250  			t.FailNow()
   251  		}
   252  		// if i < 30 {
   253  		// 	t.Logf("pass: off=%d, nBits=%d", dst0, nBits)
   254  		// 	t.Logf(" dst: %08b", orgB)
   255  		// 	t.Logf(" got: %08b", dstB)
   256  		// }
   257  	}
   258  }
   259  
   260  func TestSetBits_rand(t *testing.T) {
   261  	const testIterations = 50000
   262  	rand.Seed(time.Now().UnixNano())
   263  	for i := 0; i < testIterations; i++ {
   264  		dstB := mkRandBits()
   265  		dstS := mkBitsStr(dstB)
   266  		orgB := dupBits(dstB)
   267  		orgS := mkBitsStr(orgB)
   268  
   269  		nBits := rand.Intn(len(dstS)) + 1
   270  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   271  
   272  		wantS := orgS[:dst0] + strings.Repeat("1", nBits) + orgS[dst0+nBits:]
   273  		bitarray.SetBits(dstB, dst0, nBits)
   274  		dstS = mkBitsStr(dstB)
   275  
   276  		if dstS != wantS {
   277  			t.Errorf("unexpected result: off=%d, nBits=%d", dst0, nBits)
   278  			t.Logf(" dst: %08b", orgB)
   279  			t.Logf(" got: %08b", dstB)
   280  			t.Logf("want: %s", sfmt(wantS))
   281  			t.FailNow()
   282  		}
   283  		// if i < 30 {
   284  		// 	t.Logf("pass: off=%d, nBits=%d", dst0, nBits)
   285  		// 	t.Logf(" dst: %08b", orgB)
   286  		// 	t.Logf(" got: %08b", dstB)
   287  		// }
   288  	}
   289  }
   290  
   291  func TestToggleBits_rand(t *testing.T) {
   292  	const testIterations = 50000
   293  	rand.Seed(time.Now().UnixNano())
   294  	for i := 0; i < testIterations; i++ {
   295  		dstB := mkRandBits()
   296  		dstS := mkBitsStr(dstB)
   297  		orgB := dupBits(dstB)
   298  		orgS := mkBitsStr(orgB)
   299  
   300  		nBits := rand.Intn(len(dstS)) + 1
   301  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   302  
   303  		mapfn := func(r rune) rune {
   304  			switch r {
   305  			case '0':
   306  				return '1'
   307  			case '1':
   308  				return '0'
   309  			}
   310  			return r
   311  		}
   312  		subpS := strings.Map(mapfn, dstS[dst0:dst0+nBits])
   313  		wantS := orgS[:dst0] + subpS + orgS[dst0+nBits:]
   314  		bitarray.ToggleBits(dstB, dst0, nBits)
   315  		dstS = mkBitsStr(dstB)
   316  
   317  		if dstS != wantS {
   318  			t.Errorf("unexpected result: off=%d, nBits=%d", dst0, nBits)
   319  			t.Logf(" dst: %08b", orgB)
   320  			t.Logf(" got: %08b", dstB)
   321  			t.Logf("want: %s", sfmt(wantS))
   322  			t.FailNow()
   323  		}
   324  		// if i < 30 {
   325  		// 	t.Logf("pass: off=%d, nBits=%d", dst0, nBits)
   326  		// 	t.Logf(" dst: %08b", orgB)
   327  		// 	t.Logf(" got: %08b", dstB)
   328  		// }
   329  	}
   330  }
   331  
   332  func TestAndBits_rand(t *testing.T) {
   333  	const testIterations = 50000
   334  	rand.Seed(time.Now().UnixNano())
   335  	for i := 0; i < testIterations; i++ {
   336  		dstB, srcB := mkRandBits(), mkRandBits()
   337  		dstS, srcS := mkBitsStr(dstB), mkBitsStr(srcB)
   338  		orgB := dupBits(dstB)
   339  		orgS := mkBitsStr(orgB)
   340  
   341  		wid := len(dstS)
   342  		if len(srcS) < wid {
   343  			wid = len(srcS)
   344  		}
   345  		nBits := rand.Intn(wid) + 1
   346  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   347  		src0 := rand.Intn(len(srcS) - nBits + 1)
   348  
   349  		subpS := ""
   350  		for i := 0; i < nBits; i++ {
   351  			switch dstS[dst0+i:dst0+i+1] + srcS[src0+i:src0+i+1] {
   352  			case "11":
   353  				subpS += "1"
   354  			default:
   355  				subpS += "0"
   356  			}
   357  		}
   358  		wantS := orgS[:dst0] + subpS + orgS[dst0+nBits:]
   359  		bitarray.AndBits(dstB, srcB, dst0, src0, nBits)
   360  		dstS = mkBitsStr(dstB)
   361  
   362  		if dstS != wantS {
   363  			t.Errorf("unexpected result: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   364  			t.Logf(" dst: %08b", orgB)
   365  			t.Logf(" src: %08b", srcB)
   366  			t.Logf(" got: %08b", dstB)
   367  			t.Logf("want: %s", sfmt(wantS))
   368  			t.FailNow()
   369  		}
   370  		// if i < 30 {
   371  		// 	t.Logf("pass: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   372  		// 	t.Logf(" dst: %08b", orgB)
   373  		// 	t.Logf(" src: %08b", srcB)
   374  		// 	t.Logf(" got: %08b", dstB)
   375  		// }
   376  	}
   377  }
   378  
   379  func TestOrBits_rand(t *testing.T) {
   380  	const testIterations = 50000
   381  	rand.Seed(time.Now().UnixNano())
   382  	for i := 0; i < testIterations; i++ {
   383  		dstB, srcB := mkRandBits(), mkRandBits()
   384  		dstS, srcS := mkBitsStr(dstB), mkBitsStr(srcB)
   385  		orgB := dupBits(dstB)
   386  		orgS := mkBitsStr(orgB)
   387  
   388  		wid := len(dstS)
   389  		if len(srcS) < wid {
   390  			wid = len(srcS)
   391  		}
   392  		nBits := rand.Intn(wid) + 1
   393  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   394  		src0 := rand.Intn(len(srcS) - nBits + 1)
   395  
   396  		subpS := ""
   397  		for i := 0; i < nBits; i++ {
   398  			switch dstS[dst0+i:dst0+i+1] + srcS[src0+i:src0+i+1] {
   399  			case "00":
   400  				subpS += "0"
   401  			default:
   402  				subpS += "1"
   403  			}
   404  		}
   405  		wantS := orgS[:dst0] + subpS + orgS[dst0+nBits:]
   406  		bitarray.OrBits(dstB, srcB, dst0, src0, nBits)
   407  		dstS = mkBitsStr(dstB)
   408  
   409  		if dstS != wantS {
   410  			t.Errorf("unexpected result: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   411  			t.Logf(" dst: %08b", orgB)
   412  			t.Logf(" src: %08b", srcB)
   413  			t.Logf(" got: %08b", dstB)
   414  			t.Logf("want: %s", sfmt(wantS))
   415  			t.FailNow()
   416  		}
   417  		// if i < 30 {
   418  		// 	t.Logf("pass: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   419  		// 	t.Logf(" dst: %08b", orgB)
   420  		// 	t.Logf(" src: %08b", srcB)
   421  		// 	t.Logf(" got: %08b", dstB)
   422  		// }
   423  	}
   424  }
   425  
   426  func TestXorBits_rand(t *testing.T) {
   427  	const testIterations = 50000
   428  	rand.Seed(time.Now().UnixNano())
   429  	for i := 0; i < testIterations; i++ {
   430  		dstB, srcB := mkRandBits(), mkRandBits()
   431  		dstS, srcS := mkBitsStr(dstB), mkBitsStr(srcB)
   432  		orgB := dupBits(dstB)
   433  		orgS := mkBitsStr(orgB)
   434  
   435  		wid := len(dstS)
   436  		if len(srcS) < wid {
   437  			wid = len(srcS)
   438  		}
   439  		nBits := rand.Intn(wid) + 1
   440  		dst0 := rand.Intn(len(dstS) - nBits + 1)
   441  		src0 := rand.Intn(len(srcS) - nBits + 1)
   442  
   443  		subpS := ""
   444  		for i := 0; i < nBits; i++ {
   445  			switch dstS[dst0+i:dst0+i+1] + srcS[src0+i:src0+i+1] {
   446  			case "01", "10":
   447  				subpS += "1"
   448  			default:
   449  				subpS += "0"
   450  			}
   451  		}
   452  		wantS := orgS[:dst0] + subpS + orgS[dst0+nBits:]
   453  		bitarray.XorBits(dstB, srcB, dst0, src0, nBits)
   454  		dstS = mkBitsStr(dstB)
   455  
   456  		if dstS != wantS {
   457  			t.Errorf("unexpected result: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   458  			t.Logf(" dst: %08b", orgB)
   459  			t.Logf(" src: %08b", srcB)
   460  			t.Logf(" got: %08b", dstB)
   461  			t.Logf("want: %s", sfmt(wantS))
   462  			t.FailNow()
   463  		}
   464  		// if i < 30 {
   465  		// 	t.Logf("pass: dstOff=%d, srcOff=%d, nBits=%d", dst0, src0, nBits)
   466  		// 	t.Logf(" dst: %08b", orgB)
   467  		// 	t.Logf(" src: %08b", srcB)
   468  		// 	t.Logf(" got: %08b", dstB)
   469  		// }
   470  	}
   471  }