]> Cypherpunks repositories - gostls13.git/commitdiff
os: add a test case of copying a file itself via io.Copy
authorAndy Pan <panjf2000@gmail.com>
Mon, 5 Sep 2022 16:11:54 +0000 (00:11 +0800)
committerGopher Robot <gobot@golang.org>
Fri, 9 Sep 2022 15:34:46 +0000 (15:34 +0000)
Change-Id: Ib9746cb4f27625cb22620271b280d2da242b2fba
Reviewed-on: https://go-review.googlesource.com/c/go/+/428437
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Andy Pan <panjf2000@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>

src/os/readfrom_linux_test.go

index cb6a59abdb2cf578847aa200bfc9c822aab080b3..982a2b6330c5f82e93f34d05a32c07e2d536374c 100644 (file)
@@ -13,6 +13,7 @@ import (
        . "os"
        "path/filepath"
        "strconv"
+       "strings"
        "syscall"
        "testing"
        "time"
@@ -74,6 +75,56 @@ func TestCopyFileRange(t *testing.T) {
                mustSeekStart(t, dst2)
                mustContainData(t, dst2, data) // through traditional means
        })
+       t.Run("CopyFileItself", func(t *testing.T) {
+               hook := hookCopyFileRange(t)
+
+               f, err := os.CreateTemp("", "file-readfrom-itself-test")
+               if err != nil {
+                       t.Fatalf("failed to create tmp file: %v", err)
+               }
+               t.Cleanup(func() {
+                       f.Close()
+                       os.Remove(f.Name())
+               })
+
+               data := []byte("hello world!")
+               if _, err := f.Write(data); err != nil {
+                       t.Fatalf("failed to create and feed the file: %v", err)
+               }
+
+               if err := f.Sync(); err != nil {
+                       t.Fatalf("failed to save the file: %v", err)
+               }
+
+               // Rewind it.
+               if _, err := f.Seek(0, io.SeekStart); err != nil {
+                       t.Fatalf("failed to rewind the file: %v", err)
+               }
+
+               // Read data from the file itself.
+               if _, err := io.Copy(f, f); err != nil {
+                       t.Fatalf("failed to read from the file: %v", err)
+               }
+
+               if !hook.called || hook.written != 0 || hook.handled || hook.err != nil {
+                       t.Fatalf("poll.CopyFileRange should be called and return the EINVAL error, but got hook.called=%t, hook.err=%v", hook.called, hook.err)
+               }
+
+               // Rewind it.
+               if _, err := f.Seek(0, io.SeekStart); err != nil {
+                       t.Fatalf("failed to rewind the file: %v", err)
+               }
+
+               data2, err := io.ReadAll(f)
+               if err != nil {
+                       t.Fatalf("failed to read from the file: %v", err)
+               }
+
+               // It should wind up a double of the original data.
+               if strings.Repeat(string(data), 2) != string(data2) {
+                       t.Fatalf("data mismatch: %s != %s", string(data), string(data2))
+               }
+       })
        t.Run("NotRegular", func(t *testing.T) {
                t.Run("BothPipes", func(t *testing.T) {
                        hook := hookCopyFileRange(t)
@@ -344,6 +395,10 @@ type copyFileRangeHook struct {
        srcfd  int
        remain int64
 
+       written int64
+       handled bool
+       err     error
+
        original func(dst, src *poll.FD, remain int64) (int64, bool, error)
 }
 
@@ -354,7 +409,8 @@ func (h *copyFileRangeHook) install() {
                h.dstfd = dst.Sysfd
                h.srcfd = src.Sysfd
                h.remain = remain
-               return h.original(dst, src, remain)
+               h.written, h.handled, h.err = h.original(dst, src, remain)
+               return h.written, h.handled, h.err
        }
 }