diff --git a/memfs/memory.go b/memfs/memory.go index 6cbd7d0..be7623f 100644 --- a/memfs/memory.go +++ b/memfs/memory.go @@ -228,6 +228,7 @@ type file struct { position int64 flag int mode os.FileMode + modTime time.Time isClosed bool } @@ -291,6 +292,7 @@ func (f *file) WriteAt(p []byte, off int64) (int, error) { return 0, errors.New("write not supported") } + f.modTime = time.Now() n, err := f.content.WriteAt(p, off) f.position = off + int64(n) @@ -322,6 +324,7 @@ func (f *file) Duplicate(filename string, mode os.FileMode, flag int) billy.File content: f.content, mode: mode, flag: flag, + modTime: f.modTime, } if isTruncate(flag) { @@ -337,9 +340,10 @@ func (f *file) Duplicate(filename string, mode os.FileMode, flag int) billy.File func (f *file) Stat() (os.FileInfo, error) { return &fileInfo{ - name: f.Name(), - mode: f.mode, - size: f.content.Len(), + name: f.Name(), + mode: f.mode, + size: f.content.Len(), + modTime: f.modTime, }, nil } @@ -354,9 +358,10 @@ func (f *file) Unlock() error { } type fileInfo struct { - name string - size int - mode os.FileMode + name string + size int + mode os.FileMode + modTime time.Time } func (fi *fileInfo) Name() string { @@ -371,8 +376,8 @@ func (fi *fileInfo) Mode() os.FileMode { return fi.mode } -func (*fileInfo) ModTime() time.Time { - return time.Now() +func (fi *fileInfo) ModTime() time.Time { + return fi.modTime } func (fi *fileInfo) IsDir() bool { diff --git a/memfs/memory_test.go b/memfs/memory_test.go index 7a483cb..92a378a 100644 --- a/memfs/memory_test.go +++ b/memfs/memory_test.go @@ -6,10 +6,12 @@ import ( "os" "runtime" "testing" + "time" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/util" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRootExists(t *testing.T) { @@ -28,6 +30,39 @@ func TestCapabilities(t *testing.T) { assert.Equal(t, billy.DefaultCapabilities&^billy.LockCapability, caps) } +func TestModTime(t *testing.T) { + fs := New() + _, err := fs.Create("/file1") + require.NoError(t, err) + + if runtime.GOOS == "windows" { + time.Sleep(20 * time.Millisecond) + } + + _, err = fs.Create("/file2") + require.NoError(t, err) + + fi1a, err := fs.Stat("/file1") + require.NoError(t, err) + + fi2, err := fs.Stat("/file2") + require.NoError(t, err) + + fi1b, err := fs.Stat("/file1") + require.NoError(t, err) + + modtime := fi1a.ModTime() + + // file 1 and file 2 should have different mod times. + assert.NotEqual(t, modtime, fi2.ModTime()) + + // a new file info for the same unmodified file, should still match mod time. + assert.Equal(t, modtime, fi1b.ModTime()) + + // new calls to ModTime() retain existing mod time. + assert.Equal(t, modtime, fi1a.ModTime()) +} + func TestNegativeOffsets(t *testing.T) { fs := New() f, err := fs.Create("negative") diff --git a/memfs/storage.go b/memfs/storage.go index 16b48ce..c435f3a 100644 --- a/memfs/storage.go +++ b/memfs/storage.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" "sync" + "time" ) type storage struct { @@ -46,6 +47,7 @@ func (s *storage) New(path string, mode os.FileMode, flag int) (*file, error) { content: &content{name: name}, mode: mode, flag: flag, + modTime: time.Now(), } s.files[path] = f