|
| 1 | +// Package vfsutil implements virtual filesystem utilities. |
| 2 | +package vfsutil |
| 3 | + |
| 4 | +import ( |
| 5 | + "testing" |
| 6 | + |
| 7 | + "github.com/ncruces/go-sqlite3/vfs" |
| 8 | +) |
| 9 | + |
| 10 | +func TestWrapOpen(t *testing.T) { |
| 11 | + called := 0 |
| 12 | + |
| 13 | + WrapOpen(mockVFS{open: func(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 14 | + called++ |
| 15 | + return nil, flags, nil |
| 16 | + }}, "", 0) |
| 17 | + |
| 18 | + if called != 1 { |
| 19 | + t.Error("open not called") |
| 20 | + } |
| 21 | + |
| 22 | + WrapOpenFilename(mockVFS{open: func(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 23 | + called++ |
| 24 | + return nil, flags, nil |
| 25 | + }}, nil, 0) |
| 26 | + |
| 27 | + if called != 2 { |
| 28 | + t.Error("open not called") |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +func TestWrapOpenFilename(t *testing.T) { |
| 33 | + called := 0 |
| 34 | + |
| 35 | + WrapOpen(mockVFSFilename{openFilename: func(name *vfs.Filename, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 36 | + called++ |
| 37 | + return nil, flags, nil |
| 38 | + }}, "", 0) |
| 39 | + |
| 40 | + if called != 1 { |
| 41 | + t.Error("openFilename not called") |
| 42 | + } |
| 43 | + |
| 44 | + WrapOpenFilename(mockVFSFilename{openFilename: func(name *vfs.Filename, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 45 | + called++ |
| 46 | + return nil, flags, nil |
| 47 | + }}, nil, 0) |
| 48 | + |
| 49 | + if called != 2 { |
| 50 | + t.Error("openFilename not called") |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +func TestWrapLockState(t *testing.T) { |
| 55 | + called := 0 |
| 56 | + |
| 57 | + WrapLockState(mockFile{lockState: func() vfs.LockLevel { |
| 58 | + called++ |
| 59 | + return 0 |
| 60 | + }}) |
| 61 | + |
| 62 | + if called != 1 { |
| 63 | + t.Error("lockState not called") |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +func TestWrapPersistWAL(t *testing.T) { |
| 68 | + persist := false |
| 69 | + WrapSetPersistWAL(mockFile{setPersistWAL: func(b bool) { persist = b }}, true) |
| 70 | + if !persist { |
| 71 | + t.Error("setPersistWAL not called") |
| 72 | + } |
| 73 | + |
| 74 | + called := 0 |
| 75 | + WrapPersistWAL(mockFile{persistWAL: func() bool { called++; return persist }}) |
| 76 | + if !persist { |
| 77 | + t.Error("persistWAL not called") |
| 78 | + } |
| 79 | + if called != 1 { |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +func TestWrapPowersafeOverwrite(t *testing.T) { |
| 84 | + persist := false |
| 85 | + WrapSetPowersafeOverwrite(mockFile{setPowersafeOverwrite: func(b bool) { persist = b }}, true) |
| 86 | + if !persist { |
| 87 | + t.Error("setPowersafeOverwrite not called") |
| 88 | + } |
| 89 | + |
| 90 | + called := 0 |
| 91 | + WrapPowersafeOverwrite(mockFile{powersafeOverwrite: func() bool { called++; return persist }}) |
| 92 | + if !persist { |
| 93 | + t.Error("powersafeOverwrite not called") |
| 94 | + } |
| 95 | + if called != 1 { |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +func TestWrapChunkSize(t *testing.T) { |
| 100 | + var chunk int |
| 101 | + |
| 102 | + WrapChunkSize(mockFile{chunkSize: func(size int) { |
| 103 | + chunk = size |
| 104 | + }}, 5) |
| 105 | + |
| 106 | + if chunk != 5 { |
| 107 | + t.Error("chunkSize not called") |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +func TestWrapSizeHint(t *testing.T) { |
| 112 | + var hint int64 |
| 113 | + |
| 114 | + WrapSizeHint(mockFile{sizeHint: func(size int64) error { |
| 115 | + hint = size |
| 116 | + return nil |
| 117 | + }}, 5) |
| 118 | + |
| 119 | + if hint != 5 { |
| 120 | + t.Error("sizeHint not called") |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +func TestWrapHasMoved(t *testing.T) { |
| 125 | + called := 0 |
| 126 | + |
| 127 | + WrapHasMoved(mockFile{hasMoved: func() (bool, error) { |
| 128 | + called++ |
| 129 | + return false, nil |
| 130 | + }}) |
| 131 | + |
| 132 | + if called != 1 { |
| 133 | + t.Error("hasMoved not called") |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +func TestWrapOverwrite(t *testing.T) { |
| 138 | + called := 0 |
| 139 | + |
| 140 | + WrapOverwrite(mockFile{overwrite: func() error { |
| 141 | + called++ |
| 142 | + return nil |
| 143 | + }}) |
| 144 | + |
| 145 | + if called != 1 { |
| 146 | + t.Error("overwrite not called") |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +func TestWrapSyncSuper(t *testing.T) { |
| 151 | + called := 0 |
| 152 | + |
| 153 | + WrapSyncSuper(mockFile{syncSuper: func(super string) error { |
| 154 | + called++ |
| 155 | + return nil |
| 156 | + }}, "") |
| 157 | + |
| 158 | + if called != 1 { |
| 159 | + t.Error("syncSuper not called") |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +func TestWrapCommitPhaseTwo(t *testing.T) { |
| 164 | + called := 0 |
| 165 | + |
| 166 | + WrapCommitPhaseTwo(mockFile{commitPhaseTwo: func() error { |
| 167 | + called++ |
| 168 | + return nil |
| 169 | + }}) |
| 170 | + |
| 171 | + if called != 1 { |
| 172 | + t.Error("commitPhaseTwo not called") |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +func TestWrapBatchAtomicWrite(t *testing.T) { |
| 177 | + calledBegin := 0 |
| 178 | + calledCommit := 0 |
| 179 | + calledRollback := 0 |
| 180 | + |
| 181 | + f := mockFile{ |
| 182 | + begin: func() error { calledBegin++; return nil }, |
| 183 | + commit: func() error { calledCommit++; return nil }, |
| 184 | + rollback: func() error { calledRollback++; return nil }, |
| 185 | + } |
| 186 | + WrapBeginAtomicWrite(f) |
| 187 | + WrapCommitAtomicWrite(f) |
| 188 | + WrapRollbackAtomicWrite(f) |
| 189 | + |
| 190 | + if calledBegin != 1 { |
| 191 | + t.Error("beginAtomicWrite not called") |
| 192 | + } |
| 193 | + if calledCommit != 1 { |
| 194 | + t.Error("commitAtomicWrite not called") |
| 195 | + } |
| 196 | + if calledRollback != 1 { |
| 197 | + t.Error("rollbackAtomicWrite not called") |
| 198 | + } |
| 199 | +} |
| 200 | + |
| 201 | +func TestWrapCheckpoint(t *testing.T) { |
| 202 | + calledStart := 0 |
| 203 | + calledDone := 0 |
| 204 | + |
| 205 | + f := mockFile{ |
| 206 | + ckptStart: func() { calledStart++ }, |
| 207 | + ckptDone: func() { calledDone++ }, |
| 208 | + } |
| 209 | + WrapCheckpointStart(f) |
| 210 | + WrapCheckpointDone(f) |
| 211 | + |
| 212 | + if calledStart != 1 { |
| 213 | + t.Error("checkpointStart not called") |
| 214 | + } |
| 215 | + if calledDone != 1 { |
| 216 | + t.Error("checkpointDone not called") |
| 217 | + } |
| 218 | +} |
| 219 | + |
| 220 | +func TestWrapPragma(t *testing.T) { |
| 221 | + called := 0 |
| 222 | + |
| 223 | + val, err := WrapPragma(mockFile{ |
| 224 | + pragma: func(name, value string) (string, error) { |
| 225 | + called++ |
| 226 | + if name != "foo" || value != "bar" { |
| 227 | + t.Error("wrong pragma arguments") |
| 228 | + } |
| 229 | + return "baz", nil |
| 230 | + }, |
| 231 | + }, "foo", "bar") |
| 232 | + |
| 233 | + if called != 1 { |
| 234 | + t.Error("pragma not called") |
| 235 | + } |
| 236 | + if err != nil { |
| 237 | + t.Error(err) |
| 238 | + } |
| 239 | + if val != "baz" { |
| 240 | + t.Error("unexpected pragma return value") |
| 241 | + } |
| 242 | +} |
| 243 | + |
| 244 | +func TestWrapBusyHandler(t *testing.T) { |
| 245 | + called := 0 |
| 246 | + |
| 247 | + WrapBusyHandler(mockFile{ |
| 248 | + busyHandler: func(handler func() bool) { |
| 249 | + handler() |
| 250 | + called++ |
| 251 | + }, |
| 252 | + }, func() bool { return true }) |
| 253 | + |
| 254 | + if called != 1 { |
| 255 | + t.Error("busyHandler not called") |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +type mockVFS struct { |
| 260 | + open func(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) |
| 261 | +} |
| 262 | + |
| 263 | +func (m mockVFS) Open(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 264 | + return m.open(name, flags) |
| 265 | +} |
| 266 | + |
| 267 | +func (m mockVFS) Delete(name string, syncDir bool) error { panic("unimplemented") } |
| 268 | +func (m mockVFS) FullPathname(name string) (string, error) { panic("unimplemented") } |
| 269 | +func (m mockVFS) Access(name string, flags vfs.AccessFlag) (bool, error) { panic("unimplemented") } |
| 270 | + |
| 271 | +type mockVFSFilename struct { |
| 272 | + mockVFS |
| 273 | + openFilename func(name *vfs.Filename, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) |
| 274 | +} |
| 275 | + |
| 276 | +func (m mockVFSFilename) OpenFilename(name *vfs.Filename, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { |
| 277 | + return m.openFilename(name, flags) |
| 278 | +} |
| 279 | + |
| 280 | +type mockFile struct { |
| 281 | + lockState func() vfs.LockLevel |
| 282 | + persistWAL func() bool |
| 283 | + setPersistWAL func(bool) |
| 284 | + powersafeOverwrite func() bool |
| 285 | + setPowersafeOverwrite func(bool) |
| 286 | + chunkSize func(int) |
| 287 | + sizeHint func(int64) error |
| 288 | + hasMoved func() (bool, error) |
| 289 | + overwrite func() error |
| 290 | + syncSuper func(super string) error |
| 291 | + commitPhaseTwo func() error |
| 292 | + begin func() error |
| 293 | + commit func() error |
| 294 | + rollback func() error |
| 295 | + ckptStart func() |
| 296 | + ckptDone func() |
| 297 | + busyHandler func(func() bool) |
| 298 | + pragma func(name, value string) (string, error) |
| 299 | +} |
| 300 | + |
| 301 | +func (m mockFile) LockState() vfs.LockLevel { return m.lockState() } |
| 302 | +func (m mockFile) PersistWAL() bool { return m.persistWAL() } |
| 303 | +func (m mockFile) SetPersistWAL(v bool) { m.setPersistWAL(v) } |
| 304 | +func (m mockFile) PowersafeOverwrite() bool { return m.powersafeOverwrite() } |
| 305 | +func (m mockFile) SetPowersafeOverwrite(v bool) { m.setPowersafeOverwrite(v) } |
| 306 | +func (m mockFile) ChunkSize(s int) { m.chunkSize(s) } |
| 307 | +func (m mockFile) SizeHint(s int64) error { return m.sizeHint(s) } |
| 308 | +func (m mockFile) HasMoved() (bool, error) { return m.hasMoved() } |
| 309 | +func (m mockFile) Overwrite() error { return m.overwrite() } |
| 310 | +func (m mockFile) SyncSuper(s string) error { return m.syncSuper(s) } |
| 311 | +func (m mockFile) CommitPhaseTwo() error { return m.commitPhaseTwo() } |
| 312 | +func (m mockFile) BeginAtomicWrite() error { return m.begin() } |
| 313 | +func (m mockFile) CommitAtomicWrite() error { return m.commit() } |
| 314 | +func (m mockFile) RollbackAtomicWrite() error { return m.rollback() } |
| 315 | +func (m mockFile) CheckpointStart() { m.ckptStart() } |
| 316 | +func (m mockFile) CheckpointDone() { m.ckptDone() } |
| 317 | +func (m mockFile) BusyHandler(f func() bool) { m.busyHandler(f) } |
| 318 | +func (m mockFile) Pragma(n, v string) (string, error) { return m.pragma(n, v) } |
| 319 | + |
| 320 | +func (m mockFile) Close() error { panic("unimplemented") } |
| 321 | +func (m mockFile) ReadAt(p []byte, off int64) (n int, err error) { panic("unimplemented") } |
| 322 | +func (m mockFile) WriteAt(p []byte, off int64) (n int, err error) { panic("unimplemented") } |
| 323 | +func (m mockFile) Truncate(size int64) error { panic("unimplemented") } |
| 324 | +func (m mockFile) Sync(flags vfs.SyncFlag) error { panic("unimplemented") } |
| 325 | +func (m mockFile) Size() (int64, error) { panic("unimplemented") } |
| 326 | +func (m mockFile) Lock(lock vfs.LockLevel) error { panic("unimplemented") } |
| 327 | +func (m mockFile) Unlock(lock vfs.LockLevel) error { panic("unimplemented") } |
| 328 | +func (m mockFile) CheckReservedLock() (bool, error) { panic("unimplemented") } |
| 329 | +func (m mockFile) SectorSize() int { panic("unimplemented") } |
| 330 | +func (m mockFile) DeviceCharacteristics() vfs.DeviceCharacteristic { panic("unimplemented") } |
0 commit comments