blob: 15d7cf39fe3b2adf6197fca13eab87452b4f1b42 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
"testing"
)
// FakeFile is a file-like io.ReadWriteCloser for testing.
type FakeFile struct {
path string
*bytes.Buffer
}
// The filepath of this FakeFile.
func (f *FakeFile) Name() string {
return f.path
}
// Close implements io.WriteCloser
func (f *FakeFile) Close() error {
// Noop
return nil
}
func NewFakeFile(path string, contents string) *FakeFile {
return &FakeFile{
Buffer: bytes.NewBuffer([]byte(contents)),
path: path,
}
}
func TestRunCommand(t *testing.T) {
// Expects dump_breakpad_symbols to produce the specified summary and
// ninja depfile from the given input sources.
expectOutputs := func(t *testing.T, inputs []*FakeFile, expectedSummary string, expectedDepFile string) {
depFile := NewFakeFile("deps.d", "")
summaryFile := NewFakeFile("summary.json", "")
// Callback to mock executing the breakpad dump_syms binary.
execDumpSyms := func(args []string) ([]byte, error) {
return []byte("FAKE_SYMBOL_DATA_LINE_1\nFAKE_SYMBOL_DATA_LINE_2"), nil
}
// Callback to perform file I/O.
createFile := func(path string) (io.ReadWriteCloser, error) {
return NewFakeFile(path, ""), nil
}
// Convert input files from `[]FakeFile` to `[]io.Reader`
fileReaders := make([]io.Reader, len(inputs))
for i := range inputs {
fileReaders[i] = inputs[i]
}
// Process the input files.
summary := processIdsFiles(fileReaders, "/out/", execDumpSyms, createFile)
if err := writeSummary(summaryFile, summary); err != nil {
t.Fatalf("failed to write summary %s: %v", summaryFile.Name(), err)
}
// Extract input filepaths.
inputPaths := make([]string, len(inputs))
for i := range inputs {
inputPaths[i] = inputs[i].Name()
}
// Write the dep file
if err := writeDepFile(depFile, summaryFile.Name(), inputPaths); err != nil {
t.Fatalf("failed to write depfile %s: %v", depFilename, err)
}
// Expect matching summary.
actualSummary, err := ioutil.ReadAll(summaryFile)
if err != nil {
t.Fatal(err)
}
if string(actualSummary) != expectedSummary {
t.Errorf("expected summary: %s. Got %s", expectedSummary, actualSummary)
}
// Expect matching depfile.
actualDepFile, err := ioutil.ReadAll(depFile)
if err != nil {
t.Fatal(err)
}
if string(actualDepFile) != expectedDepFile {
t.Errorf("expected depfile: %s. Got %s", expectedDepFile, actualDepFile)
}
}
t.Run("should produce an emtpy summary if no data is provided", func(t *testing.T) {
inputSources := []*FakeFile{
NewFakeFile("idsA.txt", ""),
NewFakeFile("idsB.txt", ""),
}
expectedSummary := "{}"
expectedDepFile := fmt.Sprintf("summary.json: %s %s\n", "idsA.txt", "idsB.txt")
expectOutputs(t, inputSources, expectedSummary, expectedDepFile)
})
t.Run("should handle a single input file", func(t *testing.T) {
// Create a testing input file with fake hash values and binary paths.
inputSources := []*FakeFile{
NewFakeFile("ids.txt", strings.TrimSpace(`
01634b09 /path/to/binaryA.elf
02298167 /path/to/binaryB
025abbbc /path/to/binaryC.so
`)),
}
expectedSummary, err := json.MarshalIndent(map[string]string{
"/path/to/binaryA.elf": "/out/fe9881defb9ed1ddb9a89c38be973515f6ad7f0f.sym",
"/path/to/binaryB": "/out/f03de72df78157dd14ae1cc031ddba9873947179.sym",
"/path/to/binaryC.so": "/out/edbe4e45241c98dcde3538160073a0d6b097b780.sym",
}, "", " ")
if err != nil {
t.Fatal(err)
}
expectedDepFile := "summary.json: ids.txt\n"
expectOutputs(t, inputSources, string(expectedSummary), expectedDepFile)
})
t.Run("should handle multiple input files", func(t *testing.T) {
inputSources := []*FakeFile{
NewFakeFile("idsA.txt", strings.TrimSpace(`
01634b09 /path/to/binaryA.elf
02298167 /path/to/binaryB
025abbbc /path/to/binaryC.so
`)),
NewFakeFile("idsB.txt", strings.TrimSpace(`
01634b09 /path/to/binaryD
02298167 /path/to/binaryE
025abbbc /path/to/binaryF
`)),
}
expectedSummary, err := json.MarshalIndent(map[string]string{
"/path/to/binaryA.elf": "/out/fe9881defb9ed1ddb9a89c38be973515f6ad7f0f.sym",
"/path/to/binaryB": "/out/f03de72df78157dd14ae1cc031ddba9873947179.sym",
"/path/to/binaryC.so": "/out/edbe4e45241c98dcde3538160073a0d6b097b780.sym",
"/path/to/binaryD": "/out/8541277ee6941ac4c3c9ab2fc68edfb4c420861e.sym",
"/path/to/binaryE": "/out/906bc6368e6462a6cf7b78328a675ce57ef82209.sym",
"/path/to/binaryF": "/out/302cb9c3745652180c25e5da2ca3e420b8dd4e25.sym",
}, "", " ")
if err != nil {
t.Fatal(err)
}
expectedDepFile := "summary.json: idsA.txt idsB.txt\n"
expectOutputs(t, inputSources, string(expectedSummary), expectedDepFile)
})
t.Run("should skip duplicate binary paths", func(t *testing.T) {
inputSources := []*FakeFile{
NewFakeFile("idsA.txt", strings.TrimSpace(`
01634b09 /path/to/binaryA
02298167 /path/to/binaryB
asdf87fs /path/to/binaryC
`)),
NewFakeFile("idsB.txt", strings.TrimSpace(`
01634b09 /path/to/binaryA
02298167 /path/to/binaryB
asdf87fs /path/to/binaryC
`)),
NewFakeFile("idsC.txt", strings.TrimSpace(`
01634b09 /path/to/binaryA
02298167 /path/to/binaryB
asdf87fs /path/to/binaryC
`)),
}
expectedSummary, err := json.MarshalIndent(map[string]string{
"/path/to/binaryA": "/out/43e5a3c9eb9829f2eb11007223de1fb0b721a909.sym",
"/path/to/binaryB": "/out/f03de72df78157dd14ae1cc031ddba9873947179.sym",
"/path/to/binaryC": "/out/565de70a22c63a819a959fda8b95d6f4dfc6c1de.sym",
}, "", " ")
if err != nil {
t.Fatal(err)
}
expectedDepFile := "summary.json: idsA.txt idsB.txt idsC.txt\n"
expectOutputs(t, inputSources, string(expectedSummary), expectedDepFile)
})
}
// No tests to verify the output of dump_syms. Assume it does the right thing.