From 12acc9463244fde331f91722bea7a9862b3a51cc Mon Sep 17 00:00:00 2001 From: Fred Lotter Date: Wed, 21 Jun 2023 16:50:46 +0200 Subject: [PATCH] testutil: support empty string args in fakecommand FakeCommand allows unit tests to check which command-line arguments were passed, by recording a log of calls with their arguments. The following examples cannot be tested with FakeCommand: 1. shutdown -r "+0" "" 2. echo "" 3. configure --program-prefix "" The empty string command confuses the command parser in testutil. The issue is that both the argument (\000) and command delimiter (\000\000) uses null characters, which makes the command split operation split on the first occurrence of two null chars. This is an invalid assumption for an empty string argument, which will be presented as two argument delimiters, without anything in between, appearing like a command delimiter. To add support for this: - Change the command delimiter from \000\000 => \000\f\n\r (magic sequence) - Update the Calls() function to split the lines correctly. Testutil can now be used for testing the following command, including the case where msg is an empty string for the wall message: shutdown [OPTIONS...] [TIME] [WALL...] cmd := exec.Command("shutdown", "-r", fmt.Sprintf("+%d", mins), msg) --- internals/testutil/exec.go | 9 ++++----- internals/testutil/exec_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/internals/testutil/exec.go b/internals/testutil/exec.go index 113f7cebc..86245b0e0 100644 --- a/internals/testutil/exec.go +++ b/internals/testutil/exec.go @@ -92,7 +92,7 @@ type FakeCmd struct { // faking commands that need "\n" in their args (like zenity) // we use the following convention: // - generate \0 to separate args -// - generate \0\0 to separate commands +// - generate \0\f\n\r magic sequence to separate commands var scriptTpl = `#!/bin/bash printf "%%s" "$(basename "$0")" >> %[1]q printf '\0' >> %[1]q @@ -102,7 +102,7 @@ for arg in "$@"; do printf '\0' >> %[1]q done -printf '\0' >> %[1]q +printf '\f\n\r' >> %[1]q %s ` @@ -176,12 +176,11 @@ func (cmd *FakeCmd) Calls() [][]string { if err != nil { panic(err) } - logContent := strings.TrimSuffix(string(raw), "\000") + logContent := strings.TrimSuffix(string(raw), "\000\f\n\r") allCalls := [][]string{} - calls := strings.Split(logContent, "\000\000") + calls := strings.Split(logContent, "\000\f\n\r") for _, call := range calls { - call = strings.TrimSuffix(call, "\000") allCalls = append(allCalls, strings.Split(call, "\000")) } return allCalls diff --git a/internals/testutil/exec_test.go b/internals/testutil/exec_test.go index 47c35a777..18bf08d0b 100644 --- a/internals/testutil/exec_test.go +++ b/internals/testutil/exec_test.go @@ -34,9 +34,15 @@ func (s *fakeCommandSuite) TestFakeCommand(c *check.C) { c.Assert(err, check.IsNil) err = exec.Command("cmd", "second-run", "--arg1", "arg2", "a %s").Run() c.Assert(err, check.IsNil) + err = exec.Command("cmd", "third-run", "--arg1", "arg2", "").Run() + c.Assert(err, check.IsNil) + err = exec.Command("cmd", "forth-run", "--arg1", "arg2", "", "a %s").Run() + c.Assert(err, check.IsNil) c.Assert(fake.Calls(), check.DeepEquals, [][]string{ {"cmd", "first-run", "--arg1", "arg2", "a space"}, {"cmd", "second-run", "--arg1", "arg2", "a %s"}, + {"cmd", "third-run", "--arg1", "arg2", ""}, + {"cmd", "forth-run", "--arg1", "arg2", "", "a %s"}, }) }