mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-09 18:10:29 +00:00
fix: filesystem error when creating long filename (#1240)
This commit is contained in:
1 parent
af1c8b2719
commit
bad7f1d06c
4 files changed
+303
-5
No files matched your search
@@ -244,6 +244,81 @@ func TestReplaceInvalidFilename(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSafeFilename tests the combined filename sanitization functionality
|
||||
func TestSafeFilename(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
filename string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "short filename - no changes needed",
|
||||
filename: "test.txt",
|
||||
want: "test.txt",
|
||||
},
|
||||
{
|
||||
name: "empty filename",
|
||||
filename: "",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "invalid chars only",
|
||||
filename: "te/st:file.txt",
|
||||
want: "te_st_file.txt",
|
||||
},
|
||||
{
|
||||
name: "long filename only",
|
||||
filename: "this_is_a_very_long_filename_that_exceeds_the_maximum_allowed_length_and_should_be_truncated_properly.txt",
|
||||
want: "this_is_a_very_long_filename_that_exceeds_the_maximum_allowed_length_and_should_be_truncated_pro.txt",
|
||||
},
|
||||
{
|
||||
name: "both invalid chars and too long",
|
||||
filename: "path/to/very:long*filename?that<exceeds>filesystem|limits_and_has_invalid_characters_everywhere.pdf",
|
||||
want: "path_to_very_long*filename?that<exceeds>filesystem|limits_and_has_invalid_characters_everywhere.pdf",
|
||||
},
|
||||
{
|
||||
name: "unicode with invalid chars and truncation",
|
||||
filename: "测试/文件名:非常长的中文文件名_需要被截断_这是一个测试用的超长文件名.pdf",
|
||||
want: "测试_文件名_非常长的中文文件名_需要被截断_这是一个测试用的超长文.pdf",
|
||||
},
|
||||
{
|
||||
name: "hidden file with truncation",
|
||||
filename: ".gitignore_with_very_long_name_that_needs_truncation_and_more_characters_to_exceed_the_maximum_length",
|
||||
want: ".gitignore_with_very_long_name_that_needs_truncation_and_more_characters_to_exceed_the_maximum_lengt",
|
||||
},
|
||||
{
|
||||
name: "multiple dots and invalid chars",
|
||||
filename: "archive/tar.gz.backup:old.txt",
|
||||
want: "archive_tar.gz.backup_old.txt",
|
||||
},
|
||||
{
|
||||
name: "extension longer than reasonable",
|
||||
filename: "test.verylongextensionthatshouldnotbetreatedasextension_with_more_characters_to_exceed_maximum_length",
|
||||
want: "test.verylongextensionthatshouldnotbetreatedasextension_with_more_characters_to_exceed_maximum_lengt",
|
||||
},
|
||||
{
|
||||
name: "filename with spaces and invalid chars",
|
||||
filename: "my document/with:spaces and a very long name that needs to be truncated because it exceeds the maximum length.docx",
|
||||
want: "my document_with_spaces and a very long name that needs to be truncated because it exceeds the .docx",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := SafeFilename(tt.filename)
|
||||
if got != tt.want {
|
||||
t.Errorf("SafeFilename() = %q (len=%d), want %q (len=%d)",
|
||||
got, len(got), tt.want, len(tt.want))
|
||||
}
|
||||
// Verify result doesn't exceed MaxFilenameLength
|
||||
if len(got) > MaxFilenameLength {
|
||||
t.Errorf("SafeFilename() result length %d exceeds MaxFilenameLength %d",
|
||||
len(got), MaxFilenameLength)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplacePathPlaceholders(t *testing.T) {
|
||||
now := time.Now()
|
||||
year := fmt.Sprintf("%d", now.Year())
|
||||
@@ -315,3 +390,107 @@ func TestReplacePathPlaceholders(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestTruncateFilename tests the filename truncation functionality
|
||||
func TestTruncateFilename(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
filename string
|
||||
maxLength int
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "short filename - no truncation",
|
||||
filename: "test.txt",
|
||||
maxLength: 100,
|
||||
want: "test.txt",
|
||||
},
|
||||
{
|
||||
name: "filename at exact limit",
|
||||
filename: "abcdefghij.txt", // 14 chars
|
||||
maxLength: 14,
|
||||
want: "abcdefghij.txt",
|
||||
},
|
||||
{
|
||||
name: "long filename with extension - truncate base",
|
||||
filename: "this_is_a_very_long_filename_that_exceeds_the_maximum_allowed_length_and_should_be_truncated_properly.txt",
|
||||
maxLength: 100,
|
||||
want: "this_is_a_very_long_filename_that_exceeds_the_maximum_allowed_length_and_should_be_truncated_pro.txt",
|
||||
},
|
||||
{
|
||||
name: "long filename without extension",
|
||||
filename: "this_is_a_very_long_filename_without_extension_that_exceeds_maximum_length_and_needs_truncation",
|
||||
maxLength: 100,
|
||||
want: "this_is_a_very_long_filename_without_extension_that_exceeds_maximum_length_and_needs_truncation",
|
||||
},
|
||||
{
|
||||
name: "filename with multiple dots",
|
||||
filename: "archive.tar.gz.backup.old.file.with.many.dots.txt",
|
||||
maxLength: 30,
|
||||
want: "archive.tar.gz.backup.old..txt", // Preserves last extension
|
||||
},
|
||||
{
|
||||
name: "hidden file (starts with dot)",
|
||||
filename: ".gitignore_with_very_long_name_that_needs_truncation",
|
||||
maxLength: 30,
|
||||
want: ".gitignore_with_very_long_name",
|
||||
},
|
||||
{
|
||||
name: "only extension (no base name)",
|
||||
filename: ".txt",
|
||||
maxLength: 100,
|
||||
want: ".txt",
|
||||
},
|
||||
{
|
||||
name: "unicode characters in filename",
|
||||
filename: "测试文件名_非常长的中文文件名_需要被截断_这是一个测试用的超长文件名.pdf",
|
||||
maxLength: 50,
|
||||
want: "测试文件名_非常长的中文文件名_.pdf", // Truncated at byte boundary, preserving UTF-8
|
||||
},
|
||||
{
|
||||
name: "extension longer than reasonable (>20 chars)",
|
||||
filename: "test.verylongextensionthatshouldnotbetreatedasextension",
|
||||
maxLength: 30,
|
||||
want: "test.verylongextensionthatshou",
|
||||
},
|
||||
{
|
||||
name: "very short max length with extension",
|
||||
filename: "document.pdf",
|
||||
maxLength: 10,
|
||||
want: "docume.pdf",
|
||||
},
|
||||
{
|
||||
name: "maxLength smaller than extension",
|
||||
filename: "test.pdf",
|
||||
maxLength: 3,
|
||||
want: "tes",
|
||||
},
|
||||
{
|
||||
name: "empty filename",
|
||||
filename: "",
|
||||
maxLength: 100,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "filename with spaces",
|
||||
filename: "my document with spaces and a very long name that needs to be truncated.docx",
|
||||
maxLength: 50,
|
||||
want: "my document with spaces and a very long name .docx",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := TruncateFilename(tt.filename, tt.maxLength)
|
||||
if got != tt.want {
|
||||
t.Errorf("TruncateFilename() = %q (len=%d), want %q (len=%d)",
|
||||
got, len(got), tt.want, len(tt.want))
|
||||
}
|
||||
// Verify result doesn't exceed maxLength
|
||||
if len(got) > tt.maxLength {
|
||||
t.Errorf("TruncateFilename() result length %d exceeds maxLength %d",
|
||||
len(got), tt.maxLength)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user