github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/delta/calculator_test.go (about)

     1  package delta
     2  
     3  import (
     4  	"bytes"
     5  	"container/list"
     6  	"index/suffixarray"
     7  	"io/ioutil"
     8  	"testing"
     9  )
    10  
    11  func TestCalculator(t *testing.T) {
    12  	tests := []struct {
    13  		label    string
    14  		src, dst []byte
    15  		want     []instruction
    16  	}{
    17  		{
    18  			"No intersection",
    19  			[]byte("abc"),
    20  			[]byte("def"),
    21  			[]instruction{insert("def")},
    22  		},
    23  		{
    24  			"dst is prefix",
    25  			[]byte("defabc"),
    26  			[]byte("def"),
    27  			[]instruction{copyinst{0, 3}},
    28  		},
    29  		{
    30  			"dst is suffix",
    31  			[]byte("abcdef"),
    32  			[]byte("def"),
    33  			[]instruction{copyinst{3, 3}},
    34  		},
    35  		{
    36  			"src is substring of dst",
    37  			[]byte("def"), []byte("defabc"),
    38  			[]instruction{copyinst{0, 3}, insert("abc")},
    39  		},
    40  		{
    41  			// Mostly to make sure we don't crash if < minCopy
    42  			"small value",
    43  			[]byte("d"), []byte("d"),
    44  			[]instruction{insert("d")},
    45  		},
    46  		{
    47  			"src is embedded in dst",
    48  			[]byte("def"), []byte("abdefab"),
    49  			[]instruction{
    50  				insert("ab"),
    51  				copyinst{0, 3},
    52  				insert("ab"),
    53  			},
    54  		},
    55  		{
    56  			"random common substring",
    57  			[]byte("abDxxxAxF"), []byte("AxxxFwX"),
    58  			[]instruction{
    59  				insert("A"),
    60  				copyinst{3, 3},
    61  				insert("FwX"),
    62  			},
    63  		},
    64  	}
    65  
    66  	for _, tc := range tests {
    67  		idx := suffixarray.New(tc.src)
    68  		instructions, err := calculate(idx, tc.src, tc.dst, -1)
    69  		if err != nil {
    70  			t.Fatal(err)
    71  		}
    72  		if identicalInstructions(tc.want, instructions) != true {
    73  			t.Errorf("%s", tc.label)
    74  		}
    75  	}
    76  }
    77  
    78  func identicalInstructions(want []instruction, got *list.List) bool {
    79  	if len(want) != got.Len() {
    80  		return false
    81  	}
    82  
    83  	i := 0
    84  	for e := got.Front(); e != nil; e = e.Next() {
    85  		i1 := want[i]
    86  		if !i1.equals(e.Value.(instruction)) {
    87  			return false
    88  		}
    89  		i++
    90  	}
    91  	return true
    92  }
    93  
    94  func TestCalculatorWriteInsert(t *testing.T) {
    95  	var buf bytes.Buffer
    96  
    97  	i := insert("abc")
    98  	i.write(&buf)
    99  
   100  	// simple insert instructions
   101  	var want []byte = []byte{3, 97, 98, 99}
   102  	if got := buf.String(); got != string(want) {
   103  		t.Errorf("Simple insert: got %s want %s", got, want)
   104  	}
   105  
   106  	buf.Reset()
   107  	// long insert, needs to generate 2 insert instructions
   108  	// in the stream.
   109  	// 13 sequences of 10 characters
   110  	i = insert("0123456789" +
   111  		"0123456789" +
   112  		"0123456789" +
   113  		"0123456789" +
   114  		"0123456789" +
   115  		"0123456789" +
   116  		"0123456789" +
   117  		"0123456789" +
   118  		"0123456789" +
   119  		"0123456789" +
   120  		"0123456789" +
   121  		"0123456789" +
   122  		"0123456789")
   123  	i.write(&buf)
   124  	want = []byte{
   125  		// First 127 characters
   126  		127,
   127  		// 0-9, x12
   128  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   129  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   130  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   131  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   132  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   133  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   134  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   135  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   136  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   137  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   138  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   139  		48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
   140  		// 0-6
   141  		48, 49, 50, 51, 52, 53, 54,
   142  		// Insert for the remaining characters
   143  		3,
   144  		55, 56, 57,
   145  	}
   146  	if got := buf.String(); got != string(want) {
   147  		t.Errorf("Long insert: got %s want %s", got, want)
   148  	}
   149  
   150  }
   151  
   152  func TestCalculatorWriteCopy(t *testing.T) {
   153  	tests := []struct {
   154  		label string
   155  		i     copyinst
   156  		want  []byte
   157  	}{
   158  		{
   159  			"Length size 1 copy",
   160  			copyinst{0, 1},
   161  			[]byte{0x80 | 0x10, 1},
   162  		},
   163  		{
   164  			"Length size 2 copy",
   165  			copyinst{0, 1 << 8},
   166  			[]byte{0x80 | 0x20, 1},
   167  		},
   168  		{
   169  			"Length size 3 copy",
   170  			// can't use 1 << 16 or we'd hit
   171  			// the special case
   172  			copyinst{0, 2 << 16},
   173  			[]byte{0x80 | 0x40, 2},
   174  		},
   175  		{
   176  			"Length size 1 and 2 copy",
   177  			copyinst{0, (2 << 8) | 1},
   178  			[]byte{0x80 | 0x10 | 0x20, 1, 2},
   179  		},
   180  		{
   181  			"Length size 1 and 3 copy",
   182  			copyinst{0, (3 << 16) | 1},
   183  			[]byte{0x80 | 0x10 | 0x40, 1, 3},
   184  		},
   185  		{
   186  			"Length size 2 and 3 copy",
   187  			copyinst{0, (3 << 16) | (2 << 8)},
   188  			[]byte{0x80 | 0x20 | 0x40, 2, 3},
   189  		},
   190  		{
   191  			"Length size 1, 2 and 3 copy",
   192  			copyinst{0, (3 << 16) | (2 << 8) | 1},
   193  			[]byte{0x80 | 0x10 | 0x20 | 0x40, 1, 2, 3},
   194  		},
   195  		{
   196  			"Length special case size copy",
   197  			copyinst{0, 0x10000},
   198  			[]byte{0x80},
   199  		},
   200  		{
   201  			"Offset size 1 encoding",
   202  			copyinst{1, 0x10000},
   203  			[]byte{0x80 | 0x01, 1},
   204  		},
   205  		{
   206  			"Offset size 2 encoding",
   207  			copyinst{1 << 8, 0x10000},
   208  			[]byte{0x80 | 0x02, 1},
   209  		},
   210  		{
   211  			"Offset size 3 encoding",
   212  			copyinst{1 << 16, 0x10000},
   213  			[]byte{0x80 | 0x04, 1},
   214  		},
   215  		{
   216  			"Offset size 4 encoding",
   217  			copyinst{1 << 24, 0x10000},
   218  			[]byte{0x80 | 0x08, 1},
   219  		},
   220  		{
   221  			"Multibyte offset size encoding (bits 1 and 4)",
   222  			copyinst{4<<24 | 1, 0x10000},
   223  			[]byte{0x80 | 0x01 | 0x08, 1, 4},
   224  		},
   225  		{
   226  			"Mixed offset and length encoding",
   227  			copyinst{1<<8 | 2, 3},
   228  			[]byte{
   229  				0x80 |
   230  					0x1 | 0x2 | // offset bits
   231  					0x10, // length bits
   232  				2, 1, // offset first
   233  				3, // length second
   234  			},
   235  		},
   236  	}
   237  	var buf bytes.Buffer
   238  
   239  	for _, tc := range tests {
   240  		buf.Reset()
   241  		tc.i.write(&buf)
   242  
   243  		if got := buf.String(); got != string(tc.want) {
   244  			t.Errorf("%s: got %v want %v", tc.label, []byte(got), tc.want)
   245  		}
   246  	}
   247  }
   248  
   249  // Calculate a delta and ensure reading it resolves to the same
   250  // value
   251  func TestSanityTest(t *testing.T) {
   252  	// A random 2 instruction from TestCalculator.
   253  	// src is "def", dst is "defabc". Should result
   254  	// in both a copy and an insert.
   255  	// (was tested in TestCalculator)
   256  	var delta bytes.Buffer
   257  	base := []byte("def")
   258  	target := []byte("defabc")
   259  	Calculate(&delta, base, target, -1)
   260  
   261  	resolved := NewReader(
   262  		bytes.NewReader(delta.Bytes()),
   263  		bytes.NewReader(base),
   264  	)
   265  	val, err := ioutil.ReadAll(&resolved)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	if string(val) != string(target) {
   270  		t.Errorf("Unexpected delta resolution: got %v want %v", val, target)
   271  	}
   272  
   273  	// "Large" delta, one which gave us problems with the git test suite..
   274  	base = make([]byte, 4096)
   275  
   276  	for i := range base {
   277  		base[i] = 'c'
   278  	}
   279  	target = []byte(string(base) + "foo")
   280  	delta.Reset()
   281  	Calculate(&delta, base, target, -1)
   282  
   283  	resolved = NewReader(
   284  		bytes.NewReader(delta.Bytes()),
   285  		bytes.NewReader(base),
   286  	)
   287  	val, err = ioutil.ReadAll(&resolved)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  	if string(val) != string(target) {
   292  		t.Errorf("Unexpected delta resolution: got %v want %v", val, target)
   293  	}
   294  }