Golang程序  |  310行  |  5.81 KB

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"fmt"
	"reflect"
	"testing"

	"android/soong/third_party/zip"
)

var testCases = []struct {
	name string

	inputFiles []string
	sortGlobs  bool
	sortJava   bool
	args       []string
	excludes   []string

	outputFiles []string
	err         error
}{
	{
		name: "unsupported \\",

		args: []string{"a\\b:b"},

		err: fmt.Errorf("\\ characters are not currently supported"),
	},
	{ // This is modelled after the update package build rules in build/make/core/Makefile
		name: "filter globs",

		inputFiles: []string{
			"RADIO/a",
			"IMAGES/system.img",
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/vendor.img",
			"OTA/android-info.txt",
			"OTA/b",
		},
		args: []string{"OTA/android-info.txt:android-info.txt", "IMAGES/*.img:."},

		outputFiles: []string{
			"android-info.txt",
			"system.img",
			"recovery.img",
			"vendor.img",
		},
	},
	{
		name: "sorted filter globs",

		inputFiles: []string{
			"RADIO/a",
			"IMAGES/system.img",
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/vendor.img",
			"OTA/android-info.txt",
			"OTA/b",
		},
		sortGlobs: true,
		args:      []string{"IMAGES/*.img:.", "OTA/android-info.txt:android-info.txt"},

		outputFiles: []string{
			"recovery.img",
			"system.img",
			"vendor.img",
			"android-info.txt",
		},
	},
	{
		name: "sort all",

		inputFiles: []string{
			"RADIO/",
			"RADIO/a",
			"IMAGES/",
			"IMAGES/system.img",
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/vendor.img",
			"OTA/",
			"OTA/b",
			"OTA/android-info.txt",
		},
		sortGlobs: true,
		args:      []string{"**/*"},

		outputFiles: []string{
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/system.img",
			"IMAGES/vendor.img",
			"OTA/android-info.txt",
			"OTA/b",
			"RADIO/a",
		},
	},
	{
		name: "sort all implicit",

		inputFiles: []string{
			"RADIO/",
			"RADIO/a",
			"IMAGES/",
			"IMAGES/system.img",
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/vendor.img",
			"OTA/",
			"OTA/b",
			"OTA/android-info.txt",
		},
		sortGlobs: true,
		args:      nil,

		outputFiles: []string{
			"IMAGES/",
			"IMAGES/b.txt",
			"IMAGES/recovery.img",
			"IMAGES/system.img",
			"IMAGES/vendor.img",
			"OTA/",
			"OTA/android-info.txt",
			"OTA/b",
			"RADIO/",
			"RADIO/a",
		},
	},
	{
		name: "sort jar",

		inputFiles: []string{
			"MANIFEST.MF",
			"META-INF/MANIFEST.MF",
			"META-INF/aaa/",
			"META-INF/aaa/aaa",
			"META-INF/AAA",
			"META-INF.txt",
			"META-INF/",
			"AAA",
			"aaa",
		},
		sortJava: true,
		args:     nil,

		outputFiles: []string{
			"META-INF/",
			"META-INF/MANIFEST.MF",
			"META-INF/AAA",
			"META-INF/aaa/",
			"META-INF/aaa/aaa",
			"AAA",
			"MANIFEST.MF",
			"META-INF.txt",
			"aaa",
		},
	},
	{
		name: "double input",

		inputFiles: []string{
			"b",
			"a",
		},
		args: []string{"a:a2", "**/*"},

		outputFiles: []string{
			"a2",
			"b",
			"a",
		},
	},
	{
		name: "multiple matches",

		inputFiles: []string{
			"a/a",
		},
		args: []string{"a/a", "a/*"},

		outputFiles: []string{
			"a/a",
		},
	},
	{
		name: "multiple conflicting matches",

		inputFiles: []string{
			"a/a",
			"a/b",
		},
		args: []string{"a/b:a/a", "a/*"},

		err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
	},
	{
		name: "excludes",

		inputFiles: []string{
			"a/a",
			"a/b",
		},
		args:     nil,
		excludes: []string{"a/a"},

		outputFiles: []string{
			"a/b",
		},
	},
	{
		name: "excludes with include",

		inputFiles: []string{
			"a/a",
			"a/b",
		},
		args:     []string{"a/*"},
		excludes: []string{"a/a"},

		outputFiles: []string{
			"a/b",
		},
	},
	{
		name: "excludes with glob",

		inputFiles: []string{
			"a/a",
			"a/b",
		},
		args:     []string{"a/*"},
		excludes: []string{"a/*"},

		outputFiles: nil,
	},
}

func errorString(e error) string {
	if e == nil {
		return ""
	}
	return e.Error()
}

func TestZip2Zip(t *testing.T) {
	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			inputBuf := &bytes.Buffer{}
			outputBuf := &bytes.Buffer{}

			inputWriter := zip.NewWriter(inputBuf)
			for _, file := range testCase.inputFiles {
				w, err := inputWriter.Create(file)
				if err != nil {
					t.Fatal(err)
				}
				fmt.Fprintln(w, "test")
			}
			inputWriter.Close()
			inputBytes := inputBuf.Bytes()
			inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes)))
			if err != nil {
				t.Fatal(err)
			}

			outputWriter := zip.NewWriter(outputBuf)
			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args, testCase.excludes)
			if errorString(testCase.err) != errorString(err) {
				t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
			}

			outputWriter.Close()
			outputBytes := outputBuf.Bytes()
			outputReader, err := zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes)))
			if err != nil {
				t.Fatal(err)
			}
			var outputFiles []string
			if len(outputReader.File) > 0 {
				outputFiles = make([]string, len(outputReader.File))
				for i, file := range outputReader.File {
					outputFiles[i] = file.Name
				}
			}

			if !reflect.DeepEqual(testCase.outputFiles, outputFiles) {
				t.Fatalf("Output file list does not match:\n got: %v\nwant: %v", outputFiles, testCase.outputFiles)
			}
		})
	}
}