diff_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package diff_test
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "os"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/require"
  11. "github.com/kopia/kopia/fs"
  12. "github.com/kopia/kopia/internal/diff"
  13. )
  14. var _ fs.Entry = (*testFile)(nil)
  15. type testFile struct {
  16. modtime time.Time
  17. name string
  18. content string
  19. }
  20. func (f *testFile) IsDir() bool { return false }
  21. func (f *testFile) LocalFilesystemPath() string { return f.name }
  22. func (f *testFile) Close() {}
  23. func (f *testFile) Name() string { return f.name }
  24. func (f *testFile) Size() int64 { return int64(len(f.content)) }
  25. func (f *testFile) Mode() os.FileMode { return 0o644 }
  26. func (f *testFile) ModTime() time.Time { return f.modtime }
  27. func (f *testFile) Sys() interface{} { return nil }
  28. func (f *testFile) Owner() fs.OwnerInfo { return fs.OwnerInfo{UserID: 1000, GroupID: 1000} }
  29. func (f *testFile) Device() fs.DeviceInfo { return fs.DeviceInfo{Dev: 1} }
  30. func (f *testFile) Open(ctx context.Context) (io.Reader, error) {
  31. return strings.NewReader(f.content), nil
  32. }
  33. var _ fs.Directory = (*testDirectory)(nil)
  34. type testDirectory struct {
  35. name string
  36. files []fs.Entry
  37. modtime time.Time
  38. }
  39. func (d *testDirectory) Iterate(ctx context.Context) (fs.DirectoryIterator, error) {
  40. return fs.StaticIterator(d.files, nil), nil
  41. }
  42. func (d *testDirectory) SupportsMultipleIterations() bool { return false }
  43. func (d *testDirectory) IsDir() bool { return true }
  44. func (d *testDirectory) LocalFilesystemPath() string { return d.name }
  45. func (d *testDirectory) Close() {}
  46. func (d *testDirectory) Name() string { return d.name }
  47. func (d *testDirectory) Size() int64 { return 0 }
  48. func (d *testDirectory) Mode() os.FileMode { return 0o755 }
  49. func (d *testDirectory) ModTime() time.Time { return d.modtime }
  50. func (d *testDirectory) Sys() interface{} { return nil }
  51. func (d *testDirectory) Owner() fs.OwnerInfo { return fs.OwnerInfo{UserID: 1000, GroupID: 1000} }
  52. func (d *testDirectory) Device() fs.DeviceInfo { return fs.DeviceInfo{Dev: 1} }
  53. func (d *testDirectory) Child(ctx context.Context, name string) (fs.Entry, error) {
  54. for _, f := range d.files {
  55. if f.Name() == name {
  56. return f, nil
  57. }
  58. }
  59. return nil, fs.ErrEntryNotFound
  60. }
  61. func (d *testDirectory) Readdir(ctx context.Context) ([]fs.Entry, error) { return d.files, nil }
  62. func TestCompareEmptyDirectories(t *testing.T) {
  63. var buf bytes.Buffer
  64. ctx := context.Background()
  65. dmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  66. dir1 := createTestDirectory("testDir1", dmodtime)
  67. dir2 := createTestDirectory("testDir2", dmodtime)
  68. c, err := diff.NewComparer(&buf)
  69. require.NoError(t, err)
  70. t.Cleanup(func() {
  71. _ = c.Close()
  72. })
  73. err = c.Compare(ctx, dir1, dir2)
  74. require.NoError(t, err)
  75. require.Empty(t, buf.String())
  76. }
  77. func TestCompareIdenticalDirectories(t *testing.T) {
  78. var buf bytes.Buffer
  79. ctx := context.Background()
  80. dmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  81. fmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  82. dir1 := createTestDirectory(
  83. "testDir1",
  84. dmodtime,
  85. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime},
  86. &testFile{name: "file2.txt", content: "klmnopqrstuvwxyz", modtime: fmodtime},
  87. )
  88. dir2 := createTestDirectory(
  89. "testDir2",
  90. dmodtime,
  91. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime},
  92. &testFile{name: "file2.txt", content: "klmnopqrstuvwxyz", modtime: fmodtime},
  93. )
  94. c, err := diff.NewComparer(&buf)
  95. require.NoError(t, err)
  96. t.Cleanup(func() {
  97. _ = c.Close()
  98. })
  99. err = c.Compare(ctx, dir1, dir2)
  100. require.NoError(t, err)
  101. require.Empty(t, buf.String())
  102. }
  103. func TestCompareDifferentDirectories(t *testing.T) {
  104. var buf bytes.Buffer
  105. ctx := context.Background()
  106. dmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  107. fmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  108. dir1 := createTestDirectory(
  109. "testDir1",
  110. dmodtime,
  111. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime},
  112. &testFile{name: "file2.txt", content: "klmnopqrstuvwxyz", modtime: fmodtime},
  113. )
  114. dir2 := createTestDirectory(
  115. "testDir2",
  116. dmodtime,
  117. &testFile{name: "file3.txt", content: "abcdefghij1", modtime: fmodtime},
  118. &testFile{name: "file4.txt", content: "klmnopqrstuvwxyz2", modtime: fmodtime},
  119. )
  120. c, err := diff.NewComparer(&buf)
  121. require.NoError(t, err)
  122. t.Cleanup(func() {
  123. _ = c.Close()
  124. })
  125. expectedOutput := "added file ./file3.txt (11 bytes)\nadded file ./file4.txt (17 bytes)\n" +
  126. "removed file ./file1.txt (10 bytes)\n" +
  127. "removed file ./file2.txt (16 bytes)\n"
  128. err = c.Compare(ctx, dir1, dir2)
  129. require.NoError(t, err)
  130. require.Equal(t, buf.String(), expectedOutput)
  131. }
  132. func TestCompareDifferentDirectories_DirTimeDiff(t *testing.T) {
  133. var buf bytes.Buffer
  134. ctx := context.Background()
  135. dmodtime1 := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  136. dmodtime2 := time.Date(2022, time.April, 12, 10, 30, 0, 0, time.UTC)
  137. fmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  138. dir1 := createTestDirectory(
  139. "testDir1",
  140. dmodtime1,
  141. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime},
  142. &testFile{name: "file2.txt", content: "klmnopqrstuvwxyz", modtime: fmodtime},
  143. )
  144. dir2 := createTestDirectory(
  145. "testDir2",
  146. dmodtime2,
  147. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime},
  148. &testFile{name: "file2.txt", content: "klmnopqrstuvwxyz", modtime: fmodtime},
  149. )
  150. c, err := diff.NewComparer(&buf)
  151. require.NoError(t, err)
  152. t.Cleanup(func() {
  153. _ = c.Close()
  154. })
  155. expectedOutput := ". modification times differ: 2023-04-12 10:30:00 +0000 UTC 2022-04-12 10:30:00 +0000 UTC\n"
  156. err = c.Compare(ctx, dir1, dir2)
  157. require.NoError(t, err)
  158. require.Equal(t, buf.String(), expectedOutput)
  159. }
  160. func TestCompareDifferentDirectories_FileTimeDiff(t *testing.T) {
  161. var buf bytes.Buffer
  162. ctx := context.Background()
  163. fmodtime1 := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  164. fmodtime2 := time.Date(2022, time.April, 12, 10, 30, 0, 0, time.UTC)
  165. dmodtime := time.Date(2023, time.April, 12, 10, 30, 0, 0, time.UTC)
  166. dir1 := createTestDirectory(
  167. "testDir1",
  168. dmodtime,
  169. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime1},
  170. )
  171. dir2 := createTestDirectory(
  172. "testDir2",
  173. dmodtime,
  174. &testFile{name: "file1.txt", content: "abcdefghij", modtime: fmodtime2},
  175. )
  176. c, err := diff.NewComparer(&buf)
  177. require.NoError(t, err)
  178. t.Cleanup(func() {
  179. _ = c.Close()
  180. })
  181. expectedOutput := "./file1.txt modification times differ: 2023-04-12 10:30:00 +0000 UTC 2022-04-12 10:30:00 +0000 UTC\n"
  182. err = c.Compare(ctx, dir1, dir2)
  183. require.NoError(t, err)
  184. require.Equal(t, buf.String(), expectedOutput)
  185. }
  186. func createTestDirectory(name string, modtime time.Time, files ...fs.Entry) *testDirectory {
  187. return &testDirectory{name: name, files: files, modtime: modtime}
  188. }