Skip to content

Commit 7dc936e

Browse files
committed
feat: add warning messages for empty files
- Add warning output to stderr when empty files are detected - Implement path display mode support in FileCounter - Add getDisplayPath method for flexible path formatting - Include comprehensive tests for empty file handling - Warning messages use appropriate path format based on display mode Empty files now show: 'Warning: Empty file detected: <path>'
1 parent 6cbadde commit 7dc936e

3 files changed

Lines changed: 98 additions & 5 deletions

File tree

file.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package wordcounter
22

33
import (
4+
"fmt"
45
"io"
56
"os"
7+
"path/filepath"
68
)
79

810
// FileCounter provides character counting functionality for individual files.
911
// It implements the Counter interface and combines file I/O operations
1012
// with text analysis capabilities.
1113
type FileCounter struct {
12-
tc *Counter // Internal text counter for character analysis (private)
13-
FileName string // Absolute path to the file being analyzed
14+
tc *Counter // Internal text counter for character analysis (private)
15+
FileName string // Absolute path to the file being analyzed
16+
originalPath string // Original path as provided by user
17+
pathDisplayMode string // Path display mode: absolute or relative
1418
}
1519

1620
// NewFileCounter creates a new FileCounter instance for the specified file.
@@ -23,12 +27,19 @@ type FileCounter struct {
2327
//
2428
// Returns a configured FileCounter ready for counting operations.
2529
func NewFileCounter(filename string) *FileCounter {
30+
return NewFileCounterWithPathMode(filename, PathDisplayAbsolute)
31+
}
32+
33+
// NewFileCounterWithPathMode creates a new FileCounter with specified path display mode.
34+
func NewFileCounterWithPathMode(filename string, pathDisplayMode string) *FileCounter {
2635
tc := NewCounter()
2736
absPath := ToAbsolutePath(filename)
2837

2938
fc := &FileCounter{
30-
FileName: absPath,
31-
tc: tc,
39+
FileName: absPath,
40+
originalPath: filename,
41+
pathDisplayMode: pathDisplayMode,
42+
tc: tc,
3243
}
3344

3445
return fc
@@ -62,6 +73,12 @@ func (fc *FileCounter) Count() error {
6273
return NewFileReadError(fc.FileName, err)
6374
}
6475

76+
// Check for empty file and issue warning
77+
if len(data) == 0 {
78+
displayPath := fc.getDisplayPath()
79+
fmt.Fprintf(os.Stderr, "Warning: Empty file detected: %s\n", displayPath)
80+
}
81+
6582
if err := fc.tc.CountBytes(data); err != nil {
6683
return NewFileReadError(fc.FileName, err)
6784
}
@@ -77,10 +94,23 @@ func (fc *FileCounter) GetStats() *Stats {
7794
}
7895

7996
func (fc *FileCounter) GetRow() Row {
80-
row := append(Row{fc.FileName}, fc.tc.S.ToRow()...)
97+
displayPath := fc.getDisplayPath()
98+
row := append(Row{displayPath}, fc.tc.S.ToRow()...)
8199
return row
82100
}
83101

102+
// getDisplayPath returns the path to display based on the path display mode
103+
func (fc *FileCounter) getDisplayPath() string {
104+
if fc.pathDisplayMode == PathDisplayRelative {
105+
if fc.originalPath != "" {
106+
return fc.originalPath
107+
}
108+
// Fallback to basename if original path is not available
109+
return filepath.Base(fc.FileName)
110+
}
111+
return fc.FileName
112+
}
113+
84114
func (fc *FileCounter) GetHeader() Row {
85115
headers := append(Row{"File"}, fc.tc.S.Header()...)
86116
return headers

file_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ func TestFileCounter_Count(t *testing.T) {
8181
t.Error("FileCounter.Count() failed, expected error for non-existent file")
8282
}
8383

84+
// Test counting the words in an empty file
85+
emptyFilename := "testdata/empty.md"
86+
fc = wcg.NewFileCounter(emptyFilename)
87+
err = fc.Count()
88+
if err != nil {
89+
t.Errorf("FileCounter.Count() failed for empty file, unexpected error: %v", err)
90+
}
91+
expectedEmptyRow := wcg.Row{filepath.Join(wd, emptyFilename), 0, 0, 0, 0}
92+
emptyRow := fc.GetRow()
93+
if !reflect.DeepEqual(emptyRow, expectedEmptyRow) {
94+
t.Errorf("FileCounter.GetRow() failed for empty file, expected row: %v, got: %v", expectedEmptyRow, emptyRow)
95+
}
96+
8497
// Test counting the words in a file that should be ignored based on the ignore patterns
8598
fc = wcg.NewFileCounter(filename)
8699
err = fc.Count()
@@ -247,3 +260,53 @@ func TestFileCounter_GetStats(t *testing.T) {
247260
t.Errorf("FileCounter.GetStats() returned incorrect stats: %+v", stats)
248261
}
249262
}
263+
264+
func TestFileCounter_EmptyFileHandling(t *testing.T) {
265+
// Create a temporary empty file for testing
266+
tempFile, err := os.CreateTemp("", "empty_test_*.txt")
267+
if err != nil {
268+
t.Fatalf("Failed to create temporary file: %v", err)
269+
}
270+
defer os.Remove(tempFile.Name())
271+
tempFile.Close()
272+
273+
// Test that empty file doesn't cause errors
274+
fc := wcg.NewFileCounter(tempFile.Name())
275+
err = fc.Count()
276+
if err != nil {
277+
t.Errorf("FileCounter.Count() failed for empty file: %v", err)
278+
}
279+
280+
// Verify statistics are all zero
281+
stats := fc.GetStats()
282+
if stats.Lines != 0 || stats.ChineseChars != 0 || stats.NonChineseChars != 0 || stats.TotalChars != 0 {
283+
t.Errorf("Empty file should have zero statistics, got: Lines=%d, ChineseChars=%d, NonChineseChars=%d, TotalChars=%d",
284+
stats.Lines, stats.ChineseChars, stats.NonChineseChars, stats.TotalChars)
285+
}
286+
287+
// Test row output
288+
row := fc.GetRow()
289+
expectedRow := wcg.Row{tempFile.Name(), 0, 0, 0, 0}
290+
if !reflect.DeepEqual(row, expectedRow) {
291+
t.Errorf("Empty file row output incorrect, expected: %v, got: %v", expectedRow, row)
292+
}
293+
}
294+
295+
func TestFileCounter_PathDisplayMode(t *testing.T) {
296+
filename := "testdata/test.md"
297+
298+
// Test absolute path mode (default)
299+
fc := wcg.NewFileCounter(filename)
300+
row := fc.GetRow()
301+
expectedAbsPath := filepath.Join(wd, filename)
302+
if row[0] != expectedAbsPath {
303+
t.Errorf("Absolute path mode failed, expected: %s, got: %s", expectedAbsPath, row[0])
304+
}
305+
306+
// Test relative path mode
307+
fc = wcg.NewFileCounterWithPathMode(filename, wcg.PathDisplayRelative)
308+
row = fc.GetRow()
309+
if row[0] != filename {
310+
t.Errorf("Relative path mode failed, expected: %s, got: %s", filename, row[0])
311+
}
312+
}

testdata/empty.md

Whitespace-only changes.

0 commit comments

Comments
 (0)