From 641012b7eb5eb9f6be839e99bb237a05661b85cb 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 argument 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 113f7ceb..86245b0e 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 47c35a77..18bf08d0 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"}, }) }