66#include < QUrl>
77#include < QCollator>
88#include < QDebug>
9+ #include < QTemporaryDir>
10+ #include < QFile>
11+ #include < QFileDevice>
12+ #include < QDateTime>
913
1014#include " sort/dfilesorter.h"
1115#include " sort/dsortkeycache.h"
@@ -29,12 +33,16 @@ private Q_SLOTS:
2933 void fileSorter_sortByName ();
3034 void fileSorter_sortByName_descending ();
3135 void fileSorter_sortBySize ();
36+ void fileSorter_sortBySize_withDirs ();
37+ void fileSorter_sortBySize_descending ();
3238 void fileSorter_sortByLastModified ();
3339 void fileSorter_sortByLastRead ();
3440 void fileSorter_mixDirAndFile ();
3541 void fileSorter_separateDirAndFile ();
3642 void fileSorter_emptyList ();
3743 void fileSorter_singleItem ();
44+ void fileSorter_sortByLastModified_withSymlink ();
45+ void fileSorter_sortByLastRead_withSymlink ();
3846};
3947
4048void tst_DFileSorter::initTestCase ()
@@ -197,6 +205,117 @@ void tst_DFileSorter::fileSorter_sortBySize()
197205 QCOMPARE (sorted[2 ]->url .fileName (), QString (" large.txt" ));
198206}
199207
208+ void tst_DFileSorter::fileSorter_sortBySize_withDirs ()
209+ {
210+ // 测试按大小排序时,目录(有效大小 -1)始终排在前面(升序时)
211+ // 这与原 DLocalHelper::fileSizeByEnt 的行为一致
212+ DFileSorter::SortConfig config;
213+ config.role = DFileSorter::SortRole::Size;
214+ config.order = Qt::AscendingOrder;
215+ config.mixDirAndFile = true ; // 混排模式
216+
217+ DFileSorter sorter (config);
218+
219+ QList<QSharedPointer<DEnumerator::SortFileInfo>> files;
220+
221+ // 目录:大小通常为 4096,但有效大小应为 -1
222+ auto dir1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
223+ dir1->url = QUrl::fromLocalFile (" /test/docs" );
224+ dir1->isDir = true ;
225+ dir1->isSymLink = false ;
226+ dir1->filesize = 4096 ; // 实际大小
227+ files.append (dir1);
228+
229+ // 小文件:100 字节(小于 4096)
230+ auto file1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
231+ file1->url = QUrl::fromLocalFile (" /test/small.txt" );
232+ file1->isDir = false ;
233+ file1->filesize = 100 ;
234+ files.append (file1);
235+
236+ // 中等文件:2000 字节(小于 4096)
237+ auto file2 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
238+ file2->url = QUrl::fromLocalFile (" /test/medium.txt" );
239+ file2->isDir = false ;
240+ file2->filesize = 2000 ;
241+ files.append (file2);
242+
243+ // 大文件:10000 字节(大于 4096)
244+ auto file3 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
245+ file3->url = QUrl::fromLocalFile (" /test/large.txt" );
246+ file3->isDir = false ;
247+ file3->filesize = 10000 ;
248+ files.append (file3);
249+
250+ // 另一个目录
251+ auto dir2 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
252+ dir2->url = QUrl::fromLocalFile (" /test/apps" );
253+ dir2->isDir = true ;
254+ dir2->isSymLink = false ;
255+ dir2->filesize = 4096 ;
256+ files.append (dir2);
257+
258+ auto sorted = sorter.sort (std::move (files));
259+
260+ // 验证:升序时目录(有效大小 -1)在前,然后按文件大小排序
261+ QCOMPARE (sorted.size (), 5 );
262+ // 目录在前(按名称排序,因为大小相同都是 -1)
263+ QCOMPARE (sorted[0 ]->isDir , true );
264+ QCOMPARE (sorted[0 ]->url .fileName (), QString (" apps" ));
265+ QCOMPARE (sorted[1 ]->isDir , true );
266+ QCOMPARE (sorted[1 ]->url .fileName (), QString (" docs" ));
267+ // 文件在后(按大小排序)
268+ QCOMPARE (sorted[2 ]->isDir , false );
269+ QCOMPARE (sorted[2 ]->url .fileName (), QString (" small.txt" ));
270+ QCOMPARE (sorted[3 ]->isDir , false );
271+ QCOMPARE (sorted[3 ]->url .fileName (), QString (" medium.txt" ));
272+ QCOMPARE (sorted[4 ]->isDir , false );
273+ QCOMPARE (sorted[4 ]->url .fileName (), QString (" large.txt" ));
274+ }
275+
276+ void tst_DFileSorter::fileSorter_sortBySize_descending ()
277+ {
278+ // 测试按大小降序排序
279+ // 降序时,目录(有效大小 -1)会排到后面
280+ DFileSorter::SortConfig config;
281+ config.role = DFileSorter::SortRole::Size;
282+ config.order = Qt::DescendingOrder;
283+ config.mixDirAndFile = true ;
284+
285+ DFileSorter sorter (config);
286+
287+ QList<QSharedPointer<DEnumerator::SortFileInfo>> files;
288+
289+ // 目录(有效大小 -1)
290+ auto dir1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
291+ dir1->url = QUrl::fromLocalFile (" /test/docs" );
292+ dir1->isDir = true ;
293+ dir1->isSymLink = false ;
294+ dir1->filesize = 4096 ;
295+ files.append (dir1);
296+
297+ // 文件
298+ auto file1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
299+ file1->url = QUrl::fromLocalFile (" /test/small.txt" );
300+ file1->isDir = false ;
301+ file1->filesize = 100 ;
302+ files.append (file1);
303+
304+ auto file2 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
305+ file2->url = QUrl::fromLocalFile (" /test/large.txt" );
306+ file2->isDir = false ;
307+ file2->filesize = 10000 ;
308+ files.append (file2);
309+
310+ auto sorted = sorter.sort (std::move (files));
311+
312+ // 降序:大文件 > 小文件 > 目录(-1 最小,反转后在最后)
313+ QCOMPARE (sorted.size (), 3 );
314+ QCOMPARE (sorted[0 ]->url .fileName (), QString (" large.txt" )); // 大文件
315+ QCOMPARE (sorted[1 ]->url .fileName (), QString (" small.txt" )); // 小文件
316+ QCOMPARE (sorted[2 ]->isDir , true ); // 目录在最后
317+ }
318+
200319void tst_DFileSorter::fileSorter_sortByLastModified ()
201320{
202321 DFileSorter::SortConfig config;
@@ -386,6 +505,131 @@ void tst_DFileSorter::fileSorter_singleItem()
386505 QCOMPARE (sorted[0 ]->url .fileName (), QString (" single.txt" ));
387506}
388507
508+ void tst_DFileSorter::fileSorter_sortByLastModified_withSymlink ()
509+ {
510+ // 测试按修改时间排序时,符号链接使用其指向文件的时间
511+ // 需要创建临时文件来测试真实场景
512+ DFileSorter::SortConfig config;
513+ config.role = DFileSorter::SortRole::LastModified;
514+ config.order = Qt::AscendingOrder;
515+ config.mixDirAndFile = true ;
516+
517+ DFileSorter sorter (config);
518+
519+ // 创建临时目录和文件
520+ QTemporaryDir tempDir;
521+ QVERIFY (tempDir.isValid ());
522+
523+ QString oldFile = tempDir.path () + " /old_file.txt" ;
524+ QString newFile = tempDir.path () + " /new_file.txt" ;
525+ QString linkFile = tempDir.path () + " /link_to_old.txt" ;
526+
527+ // 创建文件
528+ {
529+ QFile f (oldFile);
530+ f.open (QIODevice::WriteOnly);
531+ f.setFileTime (QDateTime::fromSecsSinceEpoch (1000 ), QFileDevice::FileModificationTime);
532+ }
533+ {
534+ QFile f (newFile);
535+ f.open (QIODevice::WriteOnly);
536+ f.setFileTime (QDateTime::fromSecsSinceEpoch (3000 ), QFileDevice::FileModificationTime);
537+ }
538+
539+ // 创建符号链接指向旧文件
540+ QFile::link (oldFile, linkFile);
541+
542+ QList<QSharedPointer<DEnumerator::SortFileInfo>> files;
543+
544+ // 普通文件:new_file
545+ auto file1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
546+ file1->url = QUrl::fromLocalFile (newFile);
547+ file1->isDir = false ;
548+ file1->isSymLink = false ;
549+ file1->lastModifed = 3000 ;
550+ file1->lastModifedNs = 0 ;
551+ files.append (file1);
552+
553+ // 符号链接:指向 old_file(时间 1000)
554+ auto symlink1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
555+ symlink1->url = QUrl::fromLocalFile (linkFile);
556+ symlink1->isDir = false ;
557+ symlink1->isSymLink = true ;
558+ symlink1->symlinkUrl = QUrl::fromLocalFile (oldFile); // 指向目标文件
559+ symlink1->lastModifed = 2000 ; // 链接本身的时间(排序时应忽略,使用目标时间 1000)
560+ symlink1->lastModifedNs = 0 ;
561+ files.append (symlink1);
562+
563+ auto sorted = sorter.sort (std::move (files));
564+
565+ // 按修改时间升序:link_to_old(1000,目标文件时间) < new_file(3000)
566+ QCOMPARE (sorted.size (), 2 );
567+ QCOMPARE (sorted[0 ]->url .fileName (), QString (" link_to_old.txt" ));
568+ QCOMPARE (sorted[1 ]->url .fileName (), QString (" new_file.txt" ));
569+ }
570+
571+ void tst_DFileSorter::fileSorter_sortByLastRead_withSymlink ()
572+ {
573+ // 测试按访问时间排序时,符号链接使用其指向文件的时间
574+ DFileSorter::SortConfig config;
575+ config.role = DFileSorter::SortRole::LastRead;
576+ config.order = Qt::AscendingOrder;
577+ config.mixDirAndFile = true ;
578+
579+ DFileSorter sorter (config);
580+
581+ // 创建临时目录和文件
582+ QTemporaryDir tempDir;
583+ QVERIFY (tempDir.isValid ());
584+
585+ QString file1 = tempDir.path () + " /file1.txt" ;
586+ QString file2 = tempDir.path () + " /file2.txt" ;
587+ QString linkFile = tempDir.path () + " /link_to_file2.txt" ;
588+
589+ // 创建文件并设置访问时间
590+ {
591+ QFile f (file1);
592+ f.open (QIODevice::WriteOnly);
593+ f.setFileTime (QDateTime::fromSecsSinceEpoch (1000 ), QFileDevice::FileAccessTime);
594+ }
595+ {
596+ QFile f (file2);
597+ f.open (QIODevice::WriteOnly);
598+ f.setFileTime (QDateTime::fromSecsSinceEpoch (3000 ), QFileDevice::FileAccessTime);
599+ }
600+
601+ // 创建符号链接指向 file2
602+ QFile::link (file2, linkFile);
603+
604+ QList<QSharedPointer<DEnumerator::SortFileInfo>> files;
605+
606+ // 普通文件:file1(访问时间 1000)
607+ auto normalFile = QSharedPointer<DEnumerator::SortFileInfo>::create ();
608+ normalFile->url = QUrl::fromLocalFile (file1);
609+ normalFile->isDir = false ;
610+ normalFile->isSymLink = false ;
611+ normalFile->lastRead = 1000 ;
612+ normalFile->lastReadNs = 0 ;
613+ files.append (normalFile);
614+
615+ // 符号链接:指向 file2(访问时间 3000)
616+ auto symlink1 = QSharedPointer<DEnumerator::SortFileInfo>::create ();
617+ symlink1->url = QUrl::fromLocalFile (linkFile);
618+ symlink1->isDir = false ;
619+ symlink1->isSymLink = true ;
620+ symlink1->symlinkUrl = QUrl::fromLocalFile (file2); // 指向目标文件
621+ symlink1->lastRead = 2000 ; // 链接本身的时间(排序时应忽略,使用目标时间 3000)
622+ symlink1->lastReadNs = 0 ;
623+ files.append (symlink1);
624+
625+ auto sorted = sorter.sort (std::move (files));
626+
627+ // 按访问时间升序:file1(1000) < link_to_file2(3000,目标文件时间)
628+ QCOMPARE (sorted.size (), 2 );
629+ QCOMPARE (sorted[0 ]->url .fileName (), QString (" file1.txt" ));
630+ QCOMPARE (sorted[1 ]->url .fileName (), QString (" link_to_file2.txt" ));
631+ }
632+
389633int run_tst_DFileSorter (int argc, char *argv[])
390634{
391635 tst_DFileSorter tc;
0 commit comments