perf/html-runs 1e6ecdb

base64_equiv_test.go RawHistoryFolder

1package kittygraphics
2
3import (
4	"bytes"
5	"encoding/base64"
6	"fmt"
7	"math/rand"
8	"testing"
9)
10
11// legacyDecodeBase64 is the original two-pass implementation, kept as the
12// accept/reject and error-text oracle for DecodeBase64.
13func legacyDecodeBase64(encoded []byte) ([]byte, error) {
14	decoded, err := base64.StdEncoding.DecodeString(string(encoded))
15	if err == nil {
16		return decoded, nil
17	}
18	decoded, rawErr := base64.RawStdEncoding.DecodeString(string(encoded))
19	if rawErr == nil {
20		return decoded, nil
21	}
22	return nil, fmt.Errorf("%w: %v", ErrInvalidBase64, err)
23}
24
25func checkBase64Equivalent(t testing.TB, input []byte) {
26	t.Helper()
27	want, wantErr := legacyDecodeBase64(input)
28	got, gotErr := DecodeBase64(input)
29	if (wantErr == nil) != (gotErr == nil) {
30		t.Fatalf("DecodeBase64(%q) error = %v, legacy error = %v", input, gotErr, wantErr)
31	}
32	if wantErr != nil {
33		if gotErr.Error() != wantErr.Error() {
34			t.Fatalf("DecodeBase64(%q) error = %q, legacy %q", input, gotErr, wantErr)
35		}
36		if !errorsIs(gotErr, ErrInvalidBase64) {
37			t.Fatalf("DecodeBase64(%q) error %v does not wrap ErrInvalidBase64", input, gotErr)
38		}
39		return
40	}
41	if !bytes.Equal(got, want) || (got == nil) != (want == nil) {
42		t.Fatalf("DecodeBase64(%q) = %x, legacy %x", input, got, want)
43	}
44}
45
46func TestDecodeBase64MatchesLegacyRandom(t *testing.T) {
47	rng := rand.New(rand.NewSource(1))
48	alphabets := []string{
49		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
50		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\r\n",
51		"AAAA==\r\n=-_ \t\x00\xff",
52	}
53	for i := 0; i < 200000; i++ {
54		alphabet := alphabets[rng.Intn(len(alphabets))]
55		input := make([]byte, rng.Intn(24))
56		for j := range input {
57			input[j] = alphabet[rng.Intn(len(alphabet))]
58		}
59		checkBase64Equivalent(t, input)
60	}
61	// Valid encodings, padded and raw, with and without line breaks.
62	for n := 0; n < 40; n++ {
63		raw := make([]byte, n)
64		rng.Read(raw)
65		padded := base64.StdEncoding.EncodeToString(raw)
66		unpadded := base64.RawStdEncoding.EncodeToString(raw)
67		checkBase64Equivalent(t, []byte(padded))
68		checkBase64Equivalent(t, []byte(unpadded))
69		checkBase64Equivalent(t, []byte(unpadded+"\r\n"))
70		if len(padded) > 2 {
71			checkBase64Equivalent(t, []byte(padded[:2]+"\n"+padded[2:]))
72			checkBase64Equivalent(t, []byte(padded[:len(padded)-1]))
73		}
74	}
75	checkBase64Equivalent(t, nil)
76	checkBase64Equivalent(t, []byte{})
77}
78
79func FuzzDecodeBase64MatchesLegacy(f *testing.F) {
80	for _, seed := range []string{"", "AAAA", "AAA=", "AAA", "AA==", "AA", "A", "AA=", "=", "AAAA\n", "AA\r\nAA", "-_-_"} {
81		f.Add([]byte(seed))
82	}
83	f.Fuzz(func(t *testing.T, input []byte) { checkBase64Equivalent(t, input) })
84}
85
86func TestParseAPCBorrowedAliasesAndParseAPCCopies(t *testing.T) {
87	apc := []byte("\x1b_Ga=t,i=1;QUJD\x1b\\")
88	copied, err := ParseAPC(apc)
89	if err != nil {
90		t.Fatal(err)
91	}
92	borrowed, err := ParseAPCBorrowed(apc)
93	if err != nil {
94		t.Fatal(err)
95	}
96	apc[len("\x1b_Ga=t,i=1;")] = 'Z'
97	if string(copied.Payload) != "QUJD" {
98		t.Fatalf("ParseAPC payload aliased input: %q", copied.Payload)
99	}
100	if string(borrowed.Payload) != "ZUJD" {
101		t.Fatalf("ParseAPCBorrowed payload = %q, want aliased", borrowed.Payload)
102	}
103}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close