1+ // SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
2+ //
3+ // SPDX-License-Identifier: GPL-3.0-or-later
4+
5+ #include < QTest>
6+ #include < QSignalSpy>
7+ #include < QStandardItemModel>
8+ #include < QSortFilterProxyModel>
9+ #include < QRegularExpression>
10+ #include < QDebug>
11+
12+ #include " ../src/models/searchfilterproxymodel.h"
13+ #include " ../src/models/appsmodel.h"
14+ #include " ../src/models/appitem.h"
15+
16+ class TestSearchFilterProxyModel : public QObject
17+ {
18+ Q_OBJECT
19+
20+ private slots:
21+ void initTestCase ();
22+ void cleanupTestCase ();
23+
24+ void testBasicSearch ();
25+ void testChineseSearch ();
26+ void testPinyinSearch ();
27+ void testJianpinSearch ();
28+ void testSorting ();
29+ void testSpecialCharacters ();
30+
31+ private:
32+ void setupTestData ();
33+ AppItem* createTestAppItem (const QString &desktopId,
34+ const QString &name,
35+ const QString &displayName,
36+ const QString &genericName = QString(),
37+ const QString &vendor = QString(),
38+ int launchedTimes = 0);
39+ };
40+
41+ void TestSearchFilterProxyModel::initTestCase ()
42+ {
43+ // 初始化测试环境
44+ setupTestData ();
45+ }
46+
47+ void TestSearchFilterProxyModel::cleanupTestCase ()
48+ {
49+ // 清理测试环境
50+ }
51+
52+ void TestSearchFilterProxyModel::setupTestData ()
53+ {
54+ // 清空当前模型数据
55+ AppsModel::instance ().clear ();
56+
57+ // 创建测试数据
58+ QList<AppItem*> testItems;
59+
60+ // 英文应用
61+ testItems.append (createTestAppItem (" org.deepin.calculator" , " Calculator" , " Calculator" , " Calculator" , " deepin" , 10 ));
62+ testItems.append (createTestAppItem (" org.deepin.editor" , " Text Editor" , " Text Editor" , " Editor" , " deepin" , 5 ));
63+ testItems.append (createTestAppItem (" org.deepin.browser" , " Web Browser" , " Web Browser" , " Browser" , " deepin" , 20 ));
64+ testItems.append (createTestAppItem (" org.libreoffice.writer" , " LibreOffice Writer" , " LibreOffice Writer" , " " , " libreoffice" , 3 ));
65+ testItems.append (createTestAppItem (" org.gimp.GIMP" , " GIMP" , " GNU Image Manipulation Program" , " " , " gimp" , 8 ));
66+ testItems.append (createTestAppItem (" com.visualstudio.code" , " Visual Studio Code" , " Visual Studio Code" , " " , " microsoft" , 15 ));
67+
68+ // 中文应用
69+ testItems.append (createTestAppItem (" org.deepin.music" , " 音乐" , " 音乐播放器" , " 音乐" , " deepin" , 12 ));
70+ testItems.append (createTestAppItem (" org.deepin.reader" , " 阅读器" , " 文档阅读器" , " 阅读" , " deepin" , 7 ));
71+ testItems.append (createTestAppItem (" org.deepin.calendar" , " 日历" , " 日历" , " 日历" , " deepin" , 4 ));
72+
73+ // 包含特殊符号的应用
74+ testItems.append (createTestAppItem (" org.special.app1" , " App@Name" , " App@Name" , " " , " special" , 1 ));
75+ testItems.append (createTestAppItem (" org.special.app2" , " App-Name" , " App-Name" , " " , " special" , 2 ));
76+ testItems.append (createTestAppItem (" org.special.app3" , " App_Name" , " App_Name" , " " , " special" , 3 ));
77+ testItems.append (createTestAppItem (" org.special.app4" , " App+Name" , " App+Name" , " " , " special" , 4 ));
78+ testItems.append (createTestAppItem (" org.special.app5" , " App&Name" , " App&Name" , " " , " special" , 5 ));
79+ testItems.append (createTestAppItem (" org.special.app6" , " App(Name)" , " App(Name)" , " " , " special" , 6 ));
80+ testItems.append (createTestAppItem (" org.special.app7" , " App[Name]" , " App[Name]" , " " , " special" , 7 ));
81+ testItems.append (createTestAppItem (" org.special.app8" , " App{Name}" , " App{Name}" , " " , " special" , 8 ));
82+ testItems.append (createTestAppItem (" org.special.app9" , " App!Name" , " App!Name" , " " , " special" , 9 ));
83+ testItems.append (createTestAppItem (" org.special.app10" , " App#Name" , " App#Name" , " " , " special" , 10 ));
84+ testItems.append (createTestAppItem (" org.special.app11" , " App$Name" , " App$Name" , " " , " special" , 11 ));
85+ testItems.append (createTestAppItem (" org.special.app12" , " App%Name" , " App%Name" , " " , " special" , 12 ));
86+ testItems.append (createTestAppItem (" org.special.app13" , " App^Name" , " App^Name" , " " , " special" , 13 ));
87+ testItems.append (createTestAppItem (" org.special.app14" , " App*Name" , " App*Name" , " " , " special" , 14 ));
88+
89+ // 添加到模型
90+ AppsModel::instance ().appendRows (testItems);
91+ }
92+
93+ AppItem* TestSearchFilterProxyModel::createTestAppItem (const QString &desktopId,
94+ const QString &name,
95+ const QString &displayName,
96+ const QString &genericName,
97+ const QString &vendor,
98+ int launchedTimes)
99+ {
100+ AppItem *item = new AppItem (desktopId);
101+ item->setName (name);
102+ item->setDisplayName (displayName);
103+ item->setIconName (" application-default-icon" );
104+
105+ if (!genericName.isEmpty ())
106+ item->setGenericName (genericName);
107+
108+ if (!vendor.isEmpty ())
109+ item->setVendor (vendor);
110+
111+ item->setLaunchedTimes (launchedTimes);
112+
113+ return item;
114+ }
115+
116+ void TestSearchFilterProxyModel::testBasicSearch ()
117+ {
118+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
119+
120+ // 测试空搜索
121+ model.setFilterRegularExpression (QRegularExpression (" " ));
122+ QCOMPARE (model.rowCount (), AppsModel::instance ().rowCount ());
123+
124+ // 测试基本搜索 - 完全匹配
125+ model.setFilterRegularExpression (QRegularExpression (" Calculator" ));
126+ QCOMPARE (model.rowCount (), 1 );
127+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.calculator" );
128+
129+ // 测试基本搜索 - 部分匹配
130+ model.setFilterRegularExpression (QRegularExpression (" Text" ));
131+ QCOMPARE (model.rowCount (), 1 );
132+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.editor" );
133+
134+ // 测试基本搜索 - 不区分大小写
135+ model.setFilterRegularExpression (QRegularExpression (" calculator" ));
136+ QCOMPARE (model.rowCount (), 1 );
137+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.calculator" );
138+
139+ // 测试基本搜索 - 多个结果
140+ model.setFilterRegularExpression (QRegularExpression (" e" ));
141+ QVERIFY (model.rowCount () > 1 );
142+ }
143+
144+ void TestSearchFilterProxyModel::testChineseSearch ()
145+ {
146+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
147+
148+ // 测试中文完全匹配
149+ model.setFilterRegularExpression (QRegularExpression (" 音乐" ));
150+ QCOMPARE (model.rowCount (), 1 );
151+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.music" );
152+
153+ // 测试中文部分匹配
154+ model.setFilterRegularExpression (QRegularExpression (" 阅读" ));
155+ QCOMPARE (model.rowCount (), 1 );
156+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.reader" );
157+ }
158+
159+ void TestSearchFilterProxyModel::testPinyinSearch ()
160+ {
161+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
162+
163+ // 测试拼音搜索
164+ model.setFilterRegularExpression (QRegularExpression (" yinyue" ));
165+ QCOMPARE (model.rowCount (), 1 );
166+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.music" );
167+
168+ // 测试拼音部分匹配
169+ model.setFilterRegularExpression (QRegularExpression (" yuedu" ));
170+ QCOMPARE (model.rowCount (), 1 );
171+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.reader" );
172+
173+ // 测试拼音首字母匹配
174+ model.setFilterRegularExpression (QRegularExpression (" rl" ));
175+ QCOMPARE (model.rowCount (), 1 );
176+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.calendar" );
177+ }
178+
179+ void TestSearchFilterProxyModel::testJianpinSearch ()
180+ {
181+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
182+
183+ // 测试简拼搜索
184+ model.setFilterRegularExpression (QRegularExpression (" yy" ));
185+ QCOMPARE (model.rowCount (), 1 );
186+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.music" );
187+
188+ // 测试简拼部分匹配
189+ model.setFilterRegularExpression (QRegularExpression (" yd" ));
190+ QCOMPARE (model.rowCount (), 1 );
191+ QCOMPARE (model.data (model.index (0 , 0 ), AppItem::DesktopIdRole).toString (), " org.deepin.reader" );
192+ }
193+
194+ void TestSearchFilterProxyModel::testSorting ()
195+ {
196+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
197+
198+ // 测试排序 - 根据匹配权重和启动次数
199+ model.setFilterRegularExpression (QRegularExpression (" e" ));
200+ QVERIFY (model.rowCount () > 2 );
201+
202+ // 验证排序结果
203+ // 检查前几个结果是否符合预期的排序规则
204+ bool foundBrowser = false ;
205+ bool foundEditor = false ;
206+
207+ for (int i = 0 ; i < qMin (3 , model.rowCount ()); ++i) {
208+ QString desktopId = model.data (model.index (i, 0 ), AppItem::DesktopIdRole).toString ();
209+ if (desktopId == " org.deepin.browser" ) {
210+ foundBrowser = true ;
211+ } else if (desktopId == " org.deepin.editor" ) {
212+ foundEditor = true ;
213+ }
214+ }
215+
216+ // 由于浏览器的启动次数更高,它应该排在编辑器前面
217+ QVERIFY (foundBrowser);
218+ }
219+
220+ void TestSearchFilterProxyModel::testSpecialCharacters ()
221+ {
222+ SearchFilterProxyModel &model = SearchFilterProxyModel::instance ();
223+
224+ // 测试普通字符搜索 - 确保基本功能正常
225+ model.setFilterRegularExpression (QRegularExpression (" App" ));
226+ QVERIFY (model.rowCount () >= 14 );
227+
228+
229+ model.setFilterRegularExpression (QRegularExpression (" App-" ));
230+ QVERIFY (model.rowCount () > 0 );
231+
232+ model.setFilterRegularExpression (QRegularExpression (" App_" ));
233+ QVERIFY (model.rowCount () > 0 );
234+
235+
236+ bool foundSpecialApp = false ;
237+
238+ model.setFilterRegularExpression (QRegularExpression (" App" ));
239+ QVERIFY (model.rowCount () > 0 );
240+
241+ for (int i = 0 ; i < model.rowCount (); ++i) {
242+ QString desktopId = model.data (model.index (i, 0 ), AppItem::DesktopIdRole).toString ();
243+ if (desktopId.startsWith (" org.special.app" )) {
244+ foundSpecialApp = true ;
245+ break ;
246+ }
247+ }
248+
249+ QVERIFY (foundSpecialApp);
250+ }
251+
252+ QTEST_MAIN (TestSearchFilterProxyModel)
253+ #include " searchfilterproxymodeltest.moc"
0 commit comments