xref: /aosp_15_r20/build/soong/third_party/zip/writer_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2011 The Go Authors. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style
3*333d2b36SAndroid Build Coastguard Worker// license that can be found in the LICENSE file.
4*333d2b36SAndroid Build Coastguard Worker
5*333d2b36SAndroid Build Coastguard Workerpackage zip
6*333d2b36SAndroid Build Coastguard Worker
7*333d2b36SAndroid Build Coastguard Workerimport (
8*333d2b36SAndroid Build Coastguard Worker	"bytes"
9*333d2b36SAndroid Build Coastguard Worker	"io"
10*333d2b36SAndroid Build Coastguard Worker	"io/ioutil"
11*333d2b36SAndroid Build Coastguard Worker	"math/rand"
12*333d2b36SAndroid Build Coastguard Worker	"os"
13*333d2b36SAndroid Build Coastguard Worker	"testing"
14*333d2b36SAndroid Build Coastguard Worker)
15*333d2b36SAndroid Build Coastguard Worker
16*333d2b36SAndroid Build Coastguard Worker// TODO(adg): a more sophisticated test suite
17*333d2b36SAndroid Build Coastguard Worker
18*333d2b36SAndroid Build Coastguard Workertype WriteTest struct {
19*333d2b36SAndroid Build Coastguard Worker	Name   string
20*333d2b36SAndroid Build Coastguard Worker	Data   []byte
21*333d2b36SAndroid Build Coastguard Worker	Method uint16
22*333d2b36SAndroid Build Coastguard Worker	Mode   os.FileMode
23*333d2b36SAndroid Build Coastguard Worker}
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Workervar writeTests = []WriteTest{
26*333d2b36SAndroid Build Coastguard Worker	{
27*333d2b36SAndroid Build Coastguard Worker		Name:   "foo",
28*333d2b36SAndroid Build Coastguard Worker		Data:   []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
29*333d2b36SAndroid Build Coastguard Worker		Method: Store,
30*333d2b36SAndroid Build Coastguard Worker		Mode:   0666,
31*333d2b36SAndroid Build Coastguard Worker	},
32*333d2b36SAndroid Build Coastguard Worker	{
33*333d2b36SAndroid Build Coastguard Worker		Name:   "bar",
34*333d2b36SAndroid Build Coastguard Worker		Data:   nil, // large data set in the test
35*333d2b36SAndroid Build Coastguard Worker		Method: Deflate,
36*333d2b36SAndroid Build Coastguard Worker		Mode:   0644,
37*333d2b36SAndroid Build Coastguard Worker	},
38*333d2b36SAndroid Build Coastguard Worker	{
39*333d2b36SAndroid Build Coastguard Worker		Name:   "setuid",
40*333d2b36SAndroid Build Coastguard Worker		Data:   []byte("setuid file"),
41*333d2b36SAndroid Build Coastguard Worker		Method: Deflate,
42*333d2b36SAndroid Build Coastguard Worker		Mode:   0755 | os.ModeSetuid,
43*333d2b36SAndroid Build Coastguard Worker	},
44*333d2b36SAndroid Build Coastguard Worker	{
45*333d2b36SAndroid Build Coastguard Worker		Name:   "setgid",
46*333d2b36SAndroid Build Coastguard Worker		Data:   []byte("setgid file"),
47*333d2b36SAndroid Build Coastguard Worker		Method: Deflate,
48*333d2b36SAndroid Build Coastguard Worker		Mode:   0755 | os.ModeSetgid,
49*333d2b36SAndroid Build Coastguard Worker	},
50*333d2b36SAndroid Build Coastguard Worker	{
51*333d2b36SAndroid Build Coastguard Worker		Name:   "symlink",
52*333d2b36SAndroid Build Coastguard Worker		Data:   []byte("../link/target"),
53*333d2b36SAndroid Build Coastguard Worker		Method: Deflate,
54*333d2b36SAndroid Build Coastguard Worker		Mode:   0755 | os.ModeSymlink,
55*333d2b36SAndroid Build Coastguard Worker	},
56*333d2b36SAndroid Build Coastguard Worker}
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Workerfunc TestWriter(t *testing.T) {
59*333d2b36SAndroid Build Coastguard Worker	largeData := make([]byte, 1<<17)
60*333d2b36SAndroid Build Coastguard Worker	for i := range largeData {
61*333d2b36SAndroid Build Coastguard Worker		largeData[i] = byte(rand.Int())
62*333d2b36SAndroid Build Coastguard Worker	}
63*333d2b36SAndroid Build Coastguard Worker	writeTests[1].Data = largeData
64*333d2b36SAndroid Build Coastguard Worker	defer func() {
65*333d2b36SAndroid Build Coastguard Worker		writeTests[1].Data = nil
66*333d2b36SAndroid Build Coastguard Worker	}()
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Worker	// write a zip file
69*333d2b36SAndroid Build Coastguard Worker	buf := new(bytes.Buffer)
70*333d2b36SAndroid Build Coastguard Worker	w := NewWriter(buf)
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker	for _, wt := range writeTests {
73*333d2b36SAndroid Build Coastguard Worker		testCreate(t, w, &wt)
74*333d2b36SAndroid Build Coastguard Worker	}
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	if err := w.Close(); err != nil {
77*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
78*333d2b36SAndroid Build Coastguard Worker	}
79*333d2b36SAndroid Build Coastguard Worker
80*333d2b36SAndroid Build Coastguard Worker	// read it back
81*333d2b36SAndroid Build Coastguard Worker	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
82*333d2b36SAndroid Build Coastguard Worker	if err != nil {
83*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
84*333d2b36SAndroid Build Coastguard Worker	}
85*333d2b36SAndroid Build Coastguard Worker	for i, wt := range writeTests {
86*333d2b36SAndroid Build Coastguard Worker		testReadFile(t, r.File[i], &wt)
87*333d2b36SAndroid Build Coastguard Worker	}
88*333d2b36SAndroid Build Coastguard Worker}
89*333d2b36SAndroid Build Coastguard Worker
90*333d2b36SAndroid Build Coastguard Workerfunc TestWriterOffset(t *testing.T) {
91*333d2b36SAndroid Build Coastguard Worker	largeData := make([]byte, 1<<17)
92*333d2b36SAndroid Build Coastguard Worker	for i := range largeData {
93*333d2b36SAndroid Build Coastguard Worker		largeData[i] = byte(rand.Int())
94*333d2b36SAndroid Build Coastguard Worker	}
95*333d2b36SAndroid Build Coastguard Worker	writeTests[1].Data = largeData
96*333d2b36SAndroid Build Coastguard Worker	defer func() {
97*333d2b36SAndroid Build Coastguard Worker		writeTests[1].Data = nil
98*333d2b36SAndroid Build Coastguard Worker	}()
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard Worker	// write a zip file
101*333d2b36SAndroid Build Coastguard Worker	buf := new(bytes.Buffer)
102*333d2b36SAndroid Build Coastguard Worker	existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
103*333d2b36SAndroid Build Coastguard Worker	n, _ := buf.Write(existingData)
104*333d2b36SAndroid Build Coastguard Worker	w := NewWriter(buf)
105*333d2b36SAndroid Build Coastguard Worker	w.SetOffset(int64(n))
106*333d2b36SAndroid Build Coastguard Worker
107*333d2b36SAndroid Build Coastguard Worker	for _, wt := range writeTests {
108*333d2b36SAndroid Build Coastguard Worker		testCreate(t, w, &wt)
109*333d2b36SAndroid Build Coastguard Worker	}
110*333d2b36SAndroid Build Coastguard Worker
111*333d2b36SAndroid Build Coastguard Worker	if err := w.Close(); err != nil {
112*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
113*333d2b36SAndroid Build Coastguard Worker	}
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Worker	// read it back
116*333d2b36SAndroid Build Coastguard Worker	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
117*333d2b36SAndroid Build Coastguard Worker	if err != nil {
118*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
119*333d2b36SAndroid Build Coastguard Worker	}
120*333d2b36SAndroid Build Coastguard Worker	for i, wt := range writeTests {
121*333d2b36SAndroid Build Coastguard Worker		testReadFile(t, r.File[i], &wt)
122*333d2b36SAndroid Build Coastguard Worker	}
123*333d2b36SAndroid Build Coastguard Worker}
124*333d2b36SAndroid Build Coastguard Worker
125*333d2b36SAndroid Build Coastguard Workerfunc TestWriterFlush(t *testing.T) {
126*333d2b36SAndroid Build Coastguard Worker	var buf bytes.Buffer
127*333d2b36SAndroid Build Coastguard Worker	w := NewWriter(struct{ io.Writer }{&buf})
128*333d2b36SAndroid Build Coastguard Worker	_, err := w.Create("foo")
129*333d2b36SAndroid Build Coastguard Worker	if err != nil {
130*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
131*333d2b36SAndroid Build Coastguard Worker	}
132*333d2b36SAndroid Build Coastguard Worker	if buf.Len() > 0 {
133*333d2b36SAndroid Build Coastguard Worker		t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
134*333d2b36SAndroid Build Coastguard Worker	}
135*333d2b36SAndroid Build Coastguard Worker	if err := w.Flush(); err != nil {
136*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
137*333d2b36SAndroid Build Coastguard Worker	}
138*333d2b36SAndroid Build Coastguard Worker	if buf.Len() == 0 {
139*333d2b36SAndroid Build Coastguard Worker		t.Fatal("No bytes written after Flush")
140*333d2b36SAndroid Build Coastguard Worker	}
141*333d2b36SAndroid Build Coastguard Worker}
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Workerfunc testCreate(t *testing.T, w *Writer, wt *WriteTest) {
144*333d2b36SAndroid Build Coastguard Worker	header := &FileHeader{
145*333d2b36SAndroid Build Coastguard Worker		Name:   wt.Name,
146*333d2b36SAndroid Build Coastguard Worker		Method: wt.Method,
147*333d2b36SAndroid Build Coastguard Worker	}
148*333d2b36SAndroid Build Coastguard Worker	if wt.Mode != 0 {
149*333d2b36SAndroid Build Coastguard Worker		header.SetMode(wt.Mode)
150*333d2b36SAndroid Build Coastguard Worker	}
151*333d2b36SAndroid Build Coastguard Worker	f, err := w.CreateHeader(header)
152*333d2b36SAndroid Build Coastguard Worker	if err != nil {
153*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
154*333d2b36SAndroid Build Coastguard Worker	}
155*333d2b36SAndroid Build Coastguard Worker	_, err = f.Write(wt.Data)
156*333d2b36SAndroid Build Coastguard Worker	if err != nil {
157*333d2b36SAndroid Build Coastguard Worker		t.Fatal(err)
158*333d2b36SAndroid Build Coastguard Worker	}
159*333d2b36SAndroid Build Coastguard Worker}
160*333d2b36SAndroid Build Coastguard Worker
161*333d2b36SAndroid Build Coastguard Workerfunc testReadFile(t *testing.T, f *File, wt *WriteTest) {
162*333d2b36SAndroid Build Coastguard Worker	if f.Name != wt.Name {
163*333d2b36SAndroid Build Coastguard Worker		t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
164*333d2b36SAndroid Build Coastguard Worker	}
165*333d2b36SAndroid Build Coastguard Worker	testFileMode(t, wt.Name, f, wt.Mode)
166*333d2b36SAndroid Build Coastguard Worker	rc, err := f.Open()
167*333d2b36SAndroid Build Coastguard Worker	if err != nil {
168*333d2b36SAndroid Build Coastguard Worker		t.Fatal("opening:", err)
169*333d2b36SAndroid Build Coastguard Worker	}
170*333d2b36SAndroid Build Coastguard Worker	b, err := ioutil.ReadAll(rc)
171*333d2b36SAndroid Build Coastguard Worker	if err != nil {
172*333d2b36SAndroid Build Coastguard Worker		t.Fatal("reading:", err)
173*333d2b36SAndroid Build Coastguard Worker	}
174*333d2b36SAndroid Build Coastguard Worker	err = rc.Close()
175*333d2b36SAndroid Build Coastguard Worker	if err != nil {
176*333d2b36SAndroid Build Coastguard Worker		t.Fatal("closing:", err)
177*333d2b36SAndroid Build Coastguard Worker	}
178*333d2b36SAndroid Build Coastguard Worker	if !bytes.Equal(b, wt.Data) {
179*333d2b36SAndroid Build Coastguard Worker		t.Errorf("File contents %q, want %q", b, wt.Data)
180*333d2b36SAndroid Build Coastguard Worker	}
181*333d2b36SAndroid Build Coastguard Worker}
182*333d2b36SAndroid Build Coastguard Worker
183*333d2b36SAndroid Build Coastguard Workerfunc BenchmarkCompressedZipGarbage(b *testing.B) {
184*333d2b36SAndroid Build Coastguard Worker	b.ReportAllocs()
185*333d2b36SAndroid Build Coastguard Worker	var buf bytes.Buffer
186*333d2b36SAndroid Build Coastguard Worker	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
187*333d2b36SAndroid Build Coastguard Worker	for i := 0; i <= b.N; i++ {
188*333d2b36SAndroid Build Coastguard Worker		buf.Reset()
189*333d2b36SAndroid Build Coastguard Worker		zw := NewWriter(&buf)
190*333d2b36SAndroid Build Coastguard Worker		for j := 0; j < 3; j++ {
191*333d2b36SAndroid Build Coastguard Worker			w, _ := zw.CreateHeader(&FileHeader{
192*333d2b36SAndroid Build Coastguard Worker				Name:   "foo",
193*333d2b36SAndroid Build Coastguard Worker				Method: Deflate,
194*333d2b36SAndroid Build Coastguard Worker			})
195*333d2b36SAndroid Build Coastguard Worker			w.Write(bigBuf)
196*333d2b36SAndroid Build Coastguard Worker		}
197*333d2b36SAndroid Build Coastguard Worker		zw.Close()
198*333d2b36SAndroid Build Coastguard Worker		if i == 0 {
199*333d2b36SAndroid Build Coastguard Worker			// Reset the timer after the first time through.
200*333d2b36SAndroid Build Coastguard Worker			// This effectively discards the very large initial flate setup cost,
201*333d2b36SAndroid Build Coastguard Worker			// as well as the initialization of bigBuf.
202*333d2b36SAndroid Build Coastguard Worker			b.ResetTimer()
203*333d2b36SAndroid Build Coastguard Worker		}
204*333d2b36SAndroid Build Coastguard Worker	}
205*333d2b36SAndroid Build Coastguard Worker}
206