fork of go-gitdiff with jj support
at v0.8.2 5.6 kB view raw
1package gitdiff 2 3import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/rand" 8 "testing" 9) 10 11func TestLineReaderAt(t *testing.T) { 12 const lineTemplate = "generated test line %d\n" 13 14 tests := map[string]struct { 15 InputLines int 16 Offset int64 17 Count int 18 Err bool 19 EOF bool 20 EOFCount int 21 }{ 22 "readLines": { 23 InputLines: 32, 24 Offset: 0, 25 Count: 4, 26 }, 27 "readLinesOffset": { 28 InputLines: 32, 29 Offset: 8, 30 Count: 4, 31 }, 32 "readLinesLargeOffset": { 33 InputLines: 8192, 34 Offset: 4096, 35 Count: 64, 36 }, 37 "readSingleLine": { 38 InputLines: 4, 39 Offset: 2, 40 Count: 1, 41 }, 42 "readZeroLines": { 43 InputLines: 4, 44 Offset: 2, 45 Count: 0, 46 }, 47 "readAllLines": { 48 InputLines: 64, 49 Offset: 0, 50 Count: 64, 51 }, 52 "readThroughEOF": { 53 InputLines: 16, 54 Offset: 12, 55 Count: 8, 56 EOF: true, 57 EOFCount: 4, 58 }, 59 "emptyInput": { 60 InputLines: 0, 61 Offset: 0, 62 Count: 2, 63 EOF: true, 64 EOFCount: 0, 65 }, 66 "offsetAfterEOF": { 67 InputLines: 8, 68 Offset: 10, 69 Count: 2, 70 EOF: true, 71 EOFCount: 0, 72 }, 73 "offsetNegative": { 74 InputLines: 8, 75 Offset: -1, 76 Count: 2, 77 Err: true, 78 }, 79 } 80 81 for name, test := range tests { 82 t.Run(name, func(t *testing.T) { 83 var input bytes.Buffer 84 for i := 0; i < test.InputLines; i++ { 85 fmt.Fprintf(&input, lineTemplate, i) 86 } 87 88 output := make([][]byte, test.Count) 89 for i := 0; i < test.Count; i++ { 90 output[i] = []byte(fmt.Sprintf(lineTemplate, test.Offset+int64(i))) 91 } 92 93 r := &lineReaderAt{r: bytes.NewReader(input.Bytes())} 94 lines := make([][]byte, test.Count) 95 96 n, err := r.ReadLinesAt(lines, test.Offset) 97 if test.Err { 98 if err == nil { 99 t.Fatal("expected error reading lines, but got nil") 100 } 101 return 102 } 103 if err != nil && (!test.EOF || err != io.EOF) { 104 t.Fatalf("unexpected error reading lines: %v", err) 105 } 106 107 count := test.Count 108 if test.EOF { 109 count = test.EOFCount 110 } 111 112 if n != count { 113 t.Fatalf("incorrect number of lines read: expected %d, actual %d", count, n) 114 } 115 for i := 0; i < n; i++ { 116 if !bytes.Equal(output[i], lines[i]) { 117 t.Errorf("incorrect content in line %d:\nexpected: %q\nactual: %q", i, output[i], lines[i]) 118 } 119 } 120 }) 121 } 122 123 newlineTests := map[string]struct { 124 InputSize int 125 }{ 126 "readLinesNoFinalNewline": { 127 InputSize: indexBufferSize + indexBufferSize/2, 128 }, 129 "readLinesNoFinalNewlineBufferMultiple": { 130 InputSize: 4 * indexBufferSize, 131 }, 132 } 133 134 for name, test := range newlineTests { 135 t.Run(name, func(t *testing.T) { 136 input := bytes.Repeat([]byte("0"), test.InputSize) 137 138 var output [][]byte 139 for i := 0; i < len(input); i++ { 140 last := i 141 i += rand.Intn(80) 142 if i < len(input)-1 { // last character of input must not be a newline 143 input[i] = '\n' 144 output = append(output, input[last:i+1]) 145 } else { 146 output = append(output, input[last:]) 147 } 148 } 149 150 r := &lineReaderAt{r: bytes.NewReader(input)} 151 lines := make([][]byte, len(output)) 152 153 n, err := r.ReadLinesAt(lines, 0) 154 if err != nil { 155 t.Fatalf("unexpected error reading reading lines: %v", err) 156 } 157 158 if n != len(output) { 159 t.Fatalf("incorrect number of lines read: expected %d, actual %d", len(output), n) 160 } 161 162 for i, line := range lines { 163 if !bytes.Equal(output[i], line) { 164 t.Errorf("incorrect content in line %d:\nexpected: %q\nactual: %q", i, output[i], line) 165 } 166 } 167 }) 168 } 169} 170 171func TestCopyFrom(t *testing.T) { 172 tests := map[string]struct { 173 Bytes int64 174 Offset int64 175 }{ 176 "copyAll": { 177 Bytes: byteBufferSize / 2, 178 }, 179 "copyPartial": { 180 Bytes: byteBufferSize / 2, 181 Offset: byteBufferSize / 4, 182 }, 183 "copyLarge": { 184 Bytes: 8 * byteBufferSize, 185 }, 186 } 187 188 for name, test := range tests { 189 t.Run(name, func(t *testing.T) { 190 data := make([]byte, test.Bytes) 191 rand.Read(data) 192 193 var dst bytes.Buffer 194 n, err := copyFrom(&dst, bytes.NewReader(data), test.Offset) 195 if err != nil { 196 t.Fatalf("unexpected error copying data: %v", err) 197 } 198 if n != test.Bytes-test.Offset { 199 t.Fatalf("incorrect number of bytes copied: expected %d, actual %d", test.Bytes-test.Offset, n) 200 } 201 202 expected := data[test.Offset:] 203 if !bytes.Equal(expected, dst.Bytes()) { 204 t.Fatalf("incorrect data copied:\nexpected: %v\nactual: %v", expected, dst.Bytes()) 205 } 206 }) 207 } 208} 209 210func TestCopyLinesFrom(t *testing.T) { 211 tests := map[string]struct { 212 Lines int64 213 Offset int64 214 }{ 215 "copyAll": { 216 Lines: lineBufferSize / 2, 217 }, 218 "copyPartial": { 219 Lines: lineBufferSize / 2, 220 Offset: lineBufferSize / 4, 221 }, 222 "copyLarge": { 223 Lines: 8 * lineBufferSize, 224 }, 225 } 226 227 const lineLength = 128 228 229 for name, test := range tests { 230 t.Run(name, func(t *testing.T) { 231 data := make([]byte, test.Lines*lineLength) 232 for i := range data { 233 data[i] = byte(32 + rand.Intn(95)) // ascii letters, numbers, symbols 234 if i%lineLength == lineLength-1 { 235 data[i] = '\n' 236 } 237 } 238 239 var dst bytes.Buffer 240 n, err := copyLinesFrom(&dst, &lineReaderAt{r: bytes.NewReader(data)}, test.Offset) 241 if err != nil { 242 t.Fatalf("unexpected error copying data: %v", err) 243 } 244 if n != test.Lines-test.Offset { 245 t.Fatalf("incorrect number of lines copied: expected %d, actual %d", test.Lines-test.Offset, n) 246 } 247 248 expected := data[test.Offset*lineLength:] 249 if !bytes.Equal(expected, dst.Bytes()) { 250 t.Fatalf("incorrect data copied:\nexpected: %v\nactual: %v", expected, dst.Bytes()) 251 } 252 }) 253 } 254}