From 6d10c655a05824cfc3837fda034758c23776d701 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 1 May 2023 18:21:08 +0200 Subject: [PATCH] termstatus: test status line sanitization --- changelog/unreleased/pull-4318 | 8 ++++++++ internal/ui/termstatus/status.go | 27 ++++++++++++++++----------- internal/ui/termstatus/status_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 changelog/unreleased/pull-4318 diff --git a/changelog/unreleased/pull-4318 b/changelog/unreleased/pull-4318 new file mode 100644 index 000000000..198b972d3 --- /dev/null +++ b/changelog/unreleased/pull-4318 @@ -0,0 +1,8 @@ +Bugfix: Correctly clean up status bar output of the `backup` command + +Due to a regression in restic 0.15.2, the status bar of the `backup` command +could leave some output behind. This happened if filenames were printed that +are wider than the current terminal width. This has been fixed. + +https://github.com/restic/restic/issues/4319 +https://github.com/restic/restic/pull/4318 diff --git a/internal/ui/termstatus/status.go b/internal/ui/termstatus/status.go index 6939f5e28..5b310ec80 100644 --- a/internal/ui/termstatus/status.go +++ b/internal/ui/termstatus/status.go @@ -334,6 +334,21 @@ func wideRune(s string) (wide bool, utfsize uint) { return wide, uint(size) } +func sanitizeLines(lines []string, width int) []string { + // Sanitize lines and truncate them if they're too long. + for i, line := range lines { + line = Quote(line) + if width > 0 { + line = Truncate(line, width-2) + } + if i < len(lines)-1 { // Last line gets no line break. + line += "\n" + } + lines[i] = line + } + return lines +} + // SetStatus updates the status lines. // The lines should not contain newlines; this method adds them. func (t *Terminal) SetStatus(lines []string) { @@ -352,17 +367,7 @@ func (t *Terminal) SetStatus(lines []string) { } } - // Sanitize lines and truncate them if they're too long. - for i, line := range lines { - line = Quote(line) - if width > 0 { - line = Truncate(line, width-2) - } - if i < len(lines)-1 { // Last line gets no line break. - line += "\n" - } - lines[i] = line - } + sanitizeLines(lines, width) select { case t.status <- status{lines: lines}: diff --git a/internal/ui/termstatus/status_test.go b/internal/ui/termstatus/status_test.go index 9f5e15cb1..94eb734a7 100644 --- a/internal/ui/termstatus/status_test.go +++ b/internal/ui/termstatus/status_test.go @@ -1,6 +1,7 @@ package termstatus import ( + "reflect" "strconv" "testing" @@ -91,3 +92,26 @@ func BenchmarkTruncateUnicode(b *testing.B) { benchmarkTruncate(b, s, w-1) } + +func TestSanitizeLines(t *testing.T) { + var tests = []struct { + input []string + width int + output []string + }{ + {[]string{""}, 80, []string{""}}, + {[]string{"too long test line"}, 10, []string{"too long"}}, + {[]string{"too long test line", "text"}, 10, []string{"too long\n", "text"}}, + {[]string{"too long test line", "second long test line"}, 10, []string{"too long\n", "second l"}}, + } + + for _, test := range tests { + t.Run("", func(t *testing.T) { + out := sanitizeLines(test.input, test.width) + if !reflect.DeepEqual(out, test.output) { + t.Fatalf("wrong output for input %v, width %d: want %q, got %q", + test.input, test.width, test.output, out) + } + }) + } +}