Skip to content
This repository has been archived by the owner on Jan 20, 2025. It is now read-only.

Commit

Permalink
[Golang] [Package] Filesystem mock (#30)
Browse files Browse the repository at this point in the history
* Test [Golang] [Module] Fix Testing Main Command

- [+] test(main_test.go): fix assertion in TestWriteContentToFile function

* Fix [Golang] [Package] Filesystem mock

- [+] chore(file_system_mock.go): clean up comments and unused code
- [+] feat(file_system_mock.go): add support for MockFile and FileLike interfaces
- [+] fix(file_system_mock.go): fix error handling in FileExists method
  • Loading branch information
H0llyW00dzZ authored Dec 11, 2023
1 parent a6bc3fb commit 371884c
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 45 deletions.
128 changes: 85 additions & 43 deletions filesystem/file_system_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"io/fs"
"os"
"time"
"unsafe" // this package is used to convert MockFile as Expert in the Real World.

"github.com/H0llyW00dzZ/ChatGPT-Next-Web-Session-Exporter/exporter"
)
Expand All @@ -25,18 +26,17 @@ var _ FileSystem = (*MockFileSystem)(nil)
// It uses a map to store file names and associated data, allowing for the simulation of file creation,
// reading, and writing without actual file system interaction.
type MockFileSystem struct {
FilesCreated map[string]*bytes.Buffer // FilesCreated maps file names to buffers holding file contents.
WriteFileCalled bool // Add this field to track if WriteFile has been called.
WriteFilePath string // Track the path provided to WriteFile.
WriteFileData []byte // Optionally track the data provided to WriteFile.
WriteFilePerm fs.FileMode // Optionally track the file permissions provided to WriteFile.
Files map[string][]byte // Files maps file names to file contents.
ReadFileCalled bool // this field to track if ReadFile has been caled.
ReadFileData []byte // Optionally track the data provided to ReadFile.
ReadFileErr error // Optionally track the error provider to ReadFile.
FileExistsCalled bool // Optionally track the result of FileExists.
FileExistsErr error // Optionally track the error provider to FileExists.
FileExistsShouldError bool // Optionally track if FileExists should return an error.
Files map[string][]byte // Files maps file names to file contents.
WriteFileCalled bool // Track if WriteFile has been called.
WriteFilePath string // Track the path provided to WriteFile.
WriteFileData []byte // Track the data provided to WriteFile.
WriteFilePerm fs.FileMode // Track the file permissions provided to WriteFile.
FileExistsCalled bool // Track if FileExists has been called.
FileExistsErr error // Track the error to return from FileExists.
FileExistsShouldError bool // Track if FileExists should return an error.
ReadFileCalled bool // this field to track if ReadFile has been caled.
ReadFileData []byte // Optionally track the data provided to ReadFile.
ReadFileErr error // Optionally track the error provider to ReadFile.
}

// MockExporter is a mock implementation of the exporter.Exporter interface for testing purposes.
Expand All @@ -47,6 +47,27 @@ type MockExporter struct {
ErrToReturn error // ErrToReturn is the error that ConvertSessionsToCSV will return when called.
}

// mockFileInfo is a dummy implementation of fs.FileInfo used for testing.
// It provides basic implementations of the fs.FileInfo interface methods.
type mockFileInfo struct {
name string // name is the file name.
*bytes.Buffer
}

// MockFile simulates an os.File for testing purposes, may you not using this if you are not Expert.
type MockFile struct {
name string
contents *bytes.Buffer
}

// FileLike is an interface that includes the subset of *os.File methods that you need to mock.
type FileLike interface {
Close() error
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
Seek(offset int64, whence int) (int64, error)
}

// ConvertSessionsToCSV simulates the conversion of sessions to CSV format.
// It returns an error specified by ErrToReturn, allowing for error handling tests.
//
Expand All @@ -58,28 +79,34 @@ func (m *MockExporter) ConvertSessionsToCSV(ctx context.Context, sessions []expo
// NewMockFileSystem creates a new instance of MockFileSystem with initialized internal structures.
func NewMockFileSystem() *MockFileSystem {
return &MockFileSystem{
FilesCreated: make(map[string]*bytes.Buffer),
Files: make(map[string][]byte),
Files: make(map[string][]byte),
}
}

// Stat returns the FileInfo for the given file name if it exists in the mock file system.
// If the file does not exist, it returns an error to simulate the os.Stat behavior.
func (m *MockFileSystem) Stat(name string) (fs.FileInfo, error) {
if _, ok := m.FilesCreated[name]; ok {
// Return mock file information. In real tests, you might want to return a more detailed mock.
if _, ok := m.Files[name]; ok {
// Return mock file information.
return mockFileInfo{name: name}, nil
}
return nil, fs.ErrNotExist
return nil, os.ErrNotExist
}

// Create simulates the creation of a file by creating a new buffer in the FilesCreated map.
// It returns nil to signify that the file is not meant for actual I/O operations.
// Create simulates the creation of a file by adding a new entry in the Files map.
func (m *MockFileSystem) Create(name string) (*os.File, error) {
// Now Safe to create a new buffer for the file.
m.FilesCreated[name] = new(bytes.Buffer)
// Return nil to indicate that the file is not meant for I/O operations.
return nil, nil
if _, exists := m.Files[name]; exists {
return nil, os.ErrExist
}
m.Files[name] = []byte{}
mockFile := &MockFile{
name: name,
contents: bytes.NewBuffer([]byte{}),
}
// You would need to convert MockFile to *os.File using an interface or other means.
// This is a simplified example and may not work directly without additional setup.
var file *os.File = (*os.File)(unsafe.Pointer(mockFile)) // Unsafe conversion for example purposes.
return file, nil
}

// ReadFile simulates reading the content of a file from the Files map.
Expand All @@ -91,24 +118,50 @@ func (m *MockFileSystem) ReadFile(name string) ([]byte, error) {
return nil, fs.ErrNotExist
}

// WriteFile simulates writing data to a file in the FilesCreated map.
// WriteFile simulates writing data to a file in the Files map.
// It creates a new buffer with the provided data, simulating a successful write operation.
func (m *MockFileSystem) WriteFile(name string, data []byte, perm fs.FileMode) error {
if m.FilesCreated == nil {
m.Files = make(map[string][]byte)
}
m.FilesCreated[name] = bytes.NewBuffer(data)
m.Files[name] = data
m.WriteFileCalled = true // Set this to true when WriteFile is called.
m.WriteFilePath = name // Record the path.
m.WriteFileData = data // Record the data.
m.WriteFilePerm = perm // Record the permissions.
return nil
}

// mockFileInfo is a dummy implementation of fs.FileInfo used for testing.
// It provides basic implementations of the fs.FileInfo interface methods.
type mockFileInfo struct {
name string // name is the file name.
// FileExists checks if the given file name exists in the mock file system.
func (m *MockFileSystem) FileExists(name string) (bool, error) {
m.FileExistsCalled = true // Record that FileExists was called
if m.FileExistsShouldError {
return false, m.FileExistsErr
}
_, exists := m.Files[name]
return exists, nil
}

func (mf *MockFileSystem) Close() error {
// Implement the Close method if needed for testing
return nil
}

// Close simulates closing the file, it's a no-op for the mock.
func (mf *MockFile) Close() error {
return nil // No-op for the mock.
}

// Write simulates writing bytes to the file.
func (mf *MockFile) Write(p []byte) (n int, err error) {
return mf.contents.Write(p)
}

// Read simulates reading bytes from the file.
func (mf *MockFile) Read(p []byte) (n int, err error) {
return mf.contents.Read(p)
}

// Seek simulates seeking in the file, it's a no-op for the mock.
func (mf *MockFile) Seek(offset int64, whence int) (int64, error) {
return 0, nil // No-op for the mock.
}

func (m mockFileInfo) Name() string { return m.name }
Expand All @@ -117,14 +170,3 @@ func (m mockFileInfo) Mode() fs.FileMode { return 0 } // Dummy value
func (m mockFileInfo) ModTime() time.Time { return time.Time{} } // Dummy value for modification time.
func (m mockFileInfo) IsDir() bool { return false } // Dummy value, always false.
func (m mockFileInfo) Sys() interface{} { return nil } // No system-specific information.

// FileExists checks if the given file name exists in the mock file system.
func (m *MockFileSystem) FileExists(name string) (bool, error) {
m.FileExistsCalled = true // Record that FileExists was called
if m.FileExistsErr != nil {
// Simulate an error condition if an error is set
return false, nil
}
_, exists := m.Files[name] // Use the same map for all file data which can easily be mocked while touring in binary.
return exists, nil
}
4 changes: 2 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ func TestWriteContentToFile(t *testing.T) {
}

// Check the content written to the mock file system.
if string(mockFS.FilesCreated[expectedFileName].Bytes()) != content {
t.Errorf("WriteFile was called with the wrong content: got %v, want %v", string(mockFS.FilesCreated[expectedFileName].Bytes()), content)
if string(mockFS.Files[expectedFileName]) != content {
t.Errorf("WriteFile was called with the wrong content: got %v, want %v", string(mockFS.Files[expectedFileName]), content)
}
}

Expand Down

0 comments on commit 371884c

Please sign in to comment.