From 4568429a6953edc54fdc8751a5647e8554e3802c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 25 Aug 2021 08:49:30 +0300 Subject: [PATCH] main.go: remove file if on Flatten(..) failure When a Flatten() fails, the main program used to leave an incomplete file (usually zero-length). Now it will clean itself up on failure. --- main.go | 16 ++++++++------ main_test.go | 60 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/main.go b/main.go index 774b98b..661d3f0 100644 --- a/main.go +++ b/main.go @@ -53,15 +53,15 @@ type command struct { Stdout io.Writer } -func (c *command) execute(infile string, outfile string) (err error) { +func (c *command) execute(infile string, outfile string) (_err error) { rd, err := os.Open(infile) if err != nil { return err } defer func() { - err1 := rd.Close() - if err == nil { - err = err1 + err := rd.Close() + if _err == nil { + _err = err } }() @@ -74,9 +74,11 @@ func (c *command) execute(infile string, outfile string) (err error) { return fmt.Errorf("create: %w", err) } defer func() { - err1 := outf.Close() - if err == nil { - err = err1 + err := outf.Close() + if _err != nil { + os.Remove(outfile) + } else { + _err = err } }() out = outf diff --git a/main_test.go b/main_test.go index b49ed40..020aea8 100644 --- a/main_test.go +++ b/main_test.go @@ -2,8 +2,10 @@ package main import ( "bytes" + "errors" "io" "io/ioutil" + "os" "path/filepath" "regexp" "testing" @@ -13,11 +15,13 @@ func TestExecute(t *testing.T) { var _foo = []byte("foo foo") tests := []struct { - name string - fixture func(*testing.T, string) - infile string - outfile string - wantErr string + name string + fixture func(*testing.T, string) + flattener func(io.ReadSeeker, io.Writer) error + infile string + outfile string + wantErr string + assertion func(*testing.T, string) }{ { name: "ok passthrough via stdout", @@ -41,6 +45,31 @@ func TestExecute(t *testing.T) { }, outfile: "t20-out.txt", }, + { + name: "bad flattener should remove the file", + infile: "t30-in.txt", + fixture: func(t *testing.T, dir string) { + fname := filepath.Join(dir, "t30-in.txt") + if err := ioutil.WriteFile(fname, _foo, 0644); err != nil { + t.Fatalf("unexpected error: %v", err) + } + }, + flattener: flattenBad, + outfile: "t30-out.txt", + wantErr: "some error", + assertion: func(t *testing.T, dir string) { + d, err := os.ReadDir(dir) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(d) != 1 { + t.Fatalf("expected 1 entry, got %d", len(d)) + } + if d[0].Name() != "t30-in.txt" { + t.Fatalf("expected to find only t30-in.txt, got %s", d[0].Name()) + } + }, + }, { name: "infile does not exist", infile: "t3-does-not-exist.txt", @@ -57,7 +86,10 @@ func TestExecute(t *testing.T) { t.Run(tt.name, func(t *testing.T) { dir := t.TempDir() var stdout bytes.Buffer - c := &command{Stdout: &stdout} + if tt.flattener == nil { + tt.flattener = flattenPassthrough + } + if tt.fixture != nil { tt.fixture(t, dir) } @@ -65,9 +97,14 @@ func TestExecute(t *testing.T) { tt.outfile = filepath.Join(dir, tt.outfile) } inf := filepath.Join(dir, tt.infile) - c.flattener = flattenPassthrough + c := &command{Stdout: &stdout, flattener: tt.flattener} err := c.execute(inf, tt.outfile) + + if tt.assertion != nil { + tt.assertion(t, dir) + } + if tt.wantErr != "" { if err == nil { t.Fatal("expected error, got nil") @@ -78,10 +115,10 @@ func TestExecute(t *testing.T) { } return } - var out []byte if err != nil { t.Fatalf("unexpected error: %v", err) } + var out []byte if tt.outfile == "-" { out = stdout.Bytes() } else { @@ -91,8 +128,9 @@ func TestExecute(t *testing.T) { } } if !bytes.Equal([]byte("foo foo"), out) { - t.Errorf("out != foo foo: %s", string(out)) + t.Errorf("out != foo foo: %q", string(out)) } + }) } } @@ -101,3 +139,7 @@ func flattenPassthrough(r io.ReadSeeker, w io.Writer) error { _, err := io.Copy(w, r) return err } + +func flattenBad(_ io.ReadSeeker, _ io.Writer) error { + return errors.New("some error") +}