From 85830ee3a9539e66e3192d047aad86eeb1f88a08 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 16 Sep 2020 16:00:20 +0200 Subject: [PATCH] testscript: add unix2dos command --- testscript/cmd.go | 79 ++++++++++++++++++++++++++--------- testscript/testscript_test.go | 19 +++++++++ 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/testscript/cmd.go b/testscript/cmd.go index b73e6ce7..598ffe30 100644 --- a/testscript/cmd.go +++ b/testscript/cmd.go @@ -5,6 +5,8 @@ package testscript import ( + "bufio" + "bytes" "fmt" "io/ioutil" "os" @@ -24,25 +26,26 @@ import ( // NOTE: If you make changes here, update doc.go. // var scriptCmds = map[string]func(*TestScript, bool, []string){ - "cd": (*TestScript).cmdCd, - "chmod": (*TestScript).cmdChmod, - "cmp": (*TestScript).cmdCmp, - "cmpenv": (*TestScript).cmdCmpenv, - "cp": (*TestScript).cmdCp, - "env": (*TestScript).cmdEnv, - "exec": (*TestScript).cmdExec, - "exists": (*TestScript).cmdExists, - "grep": (*TestScript).cmdGrep, - "mkdir": (*TestScript).cmdMkdir, - "rm": (*TestScript).cmdRm, - "unquote": (*TestScript).cmdUnquote, - "skip": (*TestScript).cmdSkip, - "stdin": (*TestScript).cmdStdin, - "stderr": (*TestScript).cmdStderr, - "stdout": (*TestScript).cmdStdout, - "stop": (*TestScript).cmdStop, - "symlink": (*TestScript).cmdSymlink, - "wait": (*TestScript).cmdWait, + "cd": (*TestScript).cmdCd, + "chmod": (*TestScript).cmdChmod, + "cmp": (*TestScript).cmdCmp, + "cmpenv": (*TestScript).cmdCmpenv, + "cp": (*TestScript).cmdCp, + "env": (*TestScript).cmdEnv, + "exec": (*TestScript).cmdExec, + "exists": (*TestScript).cmdExists, + "grep": (*TestScript).cmdGrep, + "mkdir": (*TestScript).cmdMkdir, + "rm": (*TestScript).cmdRm, + "unquote": (*TestScript).cmdUnquote, + "skip": (*TestScript).cmdSkip, + "stdin": (*TestScript).cmdStdin, + "stderr": (*TestScript).cmdStderr, + "stdout": (*TestScript).cmdStdout, + "stop": (*TestScript).cmdStop, + "symlink": (*TestScript).cmdSymlink, + "unix2dos": (*TestScript).cmdUNIX2DOS, + "wait": (*TestScript).cmdWait, } // cd changes to a different directory. @@ -409,6 +412,26 @@ func (ts *TestScript) cmdSymlink(neg bool, args []string) { ts.Check(os.Symlink(args[2], ts.MkAbs(args[0]))) } +// cmdUNIX2DOS converts files from UNIX line endings to DOS line endings. +func (ts *TestScript) cmdUNIX2DOS(neg bool, args []string) { + if neg { + ts.Fatalf("unsupported: ! unix2dos") + } + if len(args) < 1 { + ts.Fatalf("usage: unix2dos paths...") + } + for _, arg := range args { + filename := ts.MkAbs(arg) + data, err := ioutil.ReadFile(filename) + ts.Check(err) + dosData, err := unix2DOS(data) + ts.Check(err) + if err := ioutil.WriteFile(filename, dosData, 0666); err != nil { + ts.Fatalf("%s: %v", filename, err) + } + } +} + // Tait waits for background commands to exit, setting stderr and stdout to their result. func (ts *TestScript) cmdWait(neg bool, args []string) { if neg { @@ -520,3 +543,21 @@ func scriptMatch(ts *TestScript, neg bool, args []string, text, name string) { } } } + +// unix2DOS returns data with UNIX line endings converted to DOS line endings. +func unix2DOS(data []byte) ([]byte, error) { + sb := &strings.Builder{} + s := bufio.NewScanner(bytes.NewReader(data)) + for s.Scan() { + if _, err := sb.Write(s.Bytes()); err != nil { + return nil, err + } + if _, err := sb.WriteString("\r\n"); err != nil { + return nil, err + } + } + if err := s.Err(); err != nil { + return nil, err + } + return []byte(sb.String()), nil +} diff --git a/testscript/testscript_test.go b/testscript/testscript_test.go index d9e50948..a28e3098 100644 --- a/testscript/testscript_test.go +++ b/testscript/testscript_test.go @@ -5,6 +5,7 @@ package testscript import ( + "bytes" "errors" "fmt" "io/ioutil" @@ -307,6 +308,24 @@ func TestBadDir(t *testing.T) { } } +func TestUNIX2DOS(t *testing.T) { + for data, want := range map[string]string{ + "": "", // Preserve empty files. + "\n": "\r\n", // Convert LF to CRLF in a file containing a single empty line. + "\r\n": "\r\n", // Preserve CRLF in a single line file. + "a": "a\r\n", // Append CRLF to a single line file with no line terminator. + "a\n": "a\r\n", // Convert LF to CRLF in a file containing a single non-empty line. + "a\r\n": "a\r\n", // Preserve CRLF in a file containing a single non-empty line. + "a\nb\n": "a\r\nb\r\n", // Convert LF to CRLF in multiline UNIX file. + "a\r\nb\n": "a\r\nb\r\n", // Convert LF to CRLF in a file containing a mix of UNIX and DOS lines. + "a\nb\r\n": "a\r\nb\r\n", // Convert LF to CRLF in a file containing a mix of UNIX and DOS lines. + } { + if got, err := unix2DOS([]byte(data)); err != nil || !bytes.Equal(got, []byte(want)) { + t.Errorf("unix2DOS(%q) == %q, %v, want %q, nil", data, got, err, want) + } + } +} + func setSpecialVal(ts *TestScript, neg bool, args []string) { ts.Setenv("SPECIALVAL", "42") }