]> cloud.milkyroute.net Git - dolphin.git/blob - src/tests/viewpropertiestest.cpp
ViewProperties: Store view properties in extended file attributes
[dolphin.git] / src / tests / viewpropertiestest.cpp
1 /*
2 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "views/viewproperties.h"
8 #include "dolphin_generalsettings.h"
9 #include "testdir.h"
10
11 #include <KFileMetaData/UserMetaData>
12
13 #include <QStorageInfo>
14 #include <QTest>
15
16 class ViewPropertiesTest : public QObject
17 {
18 Q_OBJECT
19
20 private Q_SLOTS:
21 void initTestCase();
22 void init();
23 void cleanup();
24
25 void testReadOnlyBehavior();
26 void testReadOnlyDirectory();
27 void testAutoSave();
28 void testParamMigrationToFileAttr();
29 void testParamMigrationToFileAttrKeepDirectory();
30 void testExtendedAttributeFull();
31
32 private:
33 bool m_globalViewProps;
34 TestDir *m_testDir;
35 };
36
37 void ViewPropertiesTest::initTestCase()
38 {
39 QStandardPaths::setTestModeEnabled(true);
40 }
41
42 void ViewPropertiesTest::init()
43 {
44 m_globalViewProps = GeneralSettings::self()->globalViewProps();
45 GeneralSettings::self()->setGlobalViewProps(false);
46 GeneralSettings::self()->save();
47
48 // It is mandatory to create the test-directory inside the home-directory
49 // of the user: ViewProperties does not write inside directories
50 // outside the home-directory to prevent overwriting other user-settings
51 // in case if write-permissions are given.
52 m_testDir = new TestDir(QDir::homePath() + "/.viewPropertiesTest-");
53 }
54
55 void ViewPropertiesTest::cleanup()
56 {
57 delete m_testDir;
58 m_testDir = nullptr;
59
60 GeneralSettings::self()->setGlobalViewProps(m_globalViewProps);
61 GeneralSettings::self()->save();
62 }
63
64 /**
65 * Test whether only reading properties won't result in creating
66 * a .directory file when destructing the ViewProperties instance
67 * and autosaving is enabled.
68 */
69 void ViewPropertiesTest::testReadOnlyBehavior()
70 {
71 QString dotDirectoryFile = m_testDir->url().toLocalFile() + "/.directory";
72 QVERIFY(!QFile::exists(dotDirectoryFile));
73
74 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
75 QVERIFY(props->isAutoSaveEnabled());
76 const QByteArray sortRole = props->sortRole();
77 Q_UNUSED(sortRole)
78 props.reset();
79
80 QVERIFY(!QFile::exists(dotDirectoryFile));
81 }
82
83 void ViewPropertiesTest::testReadOnlyDirectory()
84 {
85 auto localFolder = m_testDir->url().toLocalFile();
86 QString dotDirectoryFile = localFolder + "/.directory";
87 QVERIFY(!QFile::exists(dotDirectoryFile));
88
89 // restrict write permissions
90 QVERIFY(QFile(localFolder).setPermissions(QFileDevice::ReadOwner));
91
92 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
93 QVERIFY(props->isAutoSaveEnabled());
94 props->setSortRole("someNewSortRole");
95 props.reset();
96
97 const auto destinationDir = props->destinationDir(QStringLiteral("local")) + localFolder;
98 qDebug() << destinationDir;
99 QVERIFY(QDir(destinationDir).exists());
100
101 QVERIFY(!QFile::exists(dotDirectoryFile));
102 KFileMetaData::UserMetaData metadata(localFolder);
103 auto viewProperties = metadata.attribute(QStringLiteral("kde.fm.viewproperties#1"));
104 QVERIFY(viewProperties.isEmpty());
105
106 props.reset(new ViewProperties(m_testDir->url()));
107 QVERIFY(props->isAutoSaveEnabled());
108 QCOMPARE(props->sortRole(), "someNewSortRole");
109 props.reset();
110
111 metadata = KFileMetaData::UserMetaData(destinationDir);
112 if (metadata.isSupported()) {
113 QVERIFY(metadata.hasAttribute("kde.fm.viewproperties#1"));
114 } else {
115 QVERIFY(QFile::exists(destinationDir + "/.directory"));
116 }
117
118 // un-restrict write permissions
119 QFile(localFolder).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);
120 }
121
122 void ViewPropertiesTest::testAutoSave()
123 {
124 QString dotDirectoryFile = m_testDir->url().toLocalFile() + "/.directory";
125 QVERIFY(!QFile::exists(dotDirectoryFile));
126
127 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
128 QVERIFY(props->isAutoSaveEnabled());
129 props->setSortRole("someNewSortRole");
130 props.reset();
131
132 KFileMetaData::UserMetaData metadata(m_testDir->url().toLocalFile());
133 if (metadata.isSupported()) {
134 auto viewProperties = metadata.attribute(QStringLiteral("kde.fm.viewproperties#1"));
135 QVERIFY(!viewProperties.isEmpty());
136 QVERIFY(!QFile::exists(dotDirectoryFile));
137 } else {
138 QVERIFY(QFile::exists(dotDirectoryFile));
139 }
140 }
141
142 void ViewPropertiesTest::testParamMigrationToFileAttr()
143 {
144 QString dotDirectoryFilePath = m_testDir->url().toLocalFile() + "/.directory";
145 QVERIFY(!QFile::exists(dotDirectoryFilePath));
146
147 const char *settingsContent = R"SETTINGS("
148 [Dolphin]
149 Version=4
150 ViewMode=1
151 Timestamp=2023,12,29,10,44,15.793
152 VisibleRoles=text,CustomizedDetails,Details_text,Details_modificationtime,Details_type
153
154 [Settings]
155 HiddenFilesShown=true)SETTINGS";
156 auto dotDirectoryFile = QFile(dotDirectoryFilePath);
157 QVERIFY(dotDirectoryFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate));
158 QTextStream out(&dotDirectoryFile);
159 out << settingsContent;
160 dotDirectoryFile.close();
161
162 KFileMetaData::UserMetaData metadata(m_testDir->url().toLocalFile());
163 {
164 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
165 QCOMPARE(props->viewMode(), DolphinView::Mode::DetailsView);
166 QVERIFY(props->hiddenFilesShown());
167 props->save();
168
169 if (metadata.isSupported()) {
170 auto viewProperties = metadata.attribute(QStringLiteral("kde.fm.viewproperties#1"));
171 QVERIFY(!viewProperties.isEmpty());
172 QVERIFY(!QFile::exists(dotDirectoryFilePath));
173 } else {
174 QVERIFY(QFile::exists(dotDirectoryFilePath));
175 }
176 }
177
178 ViewProperties props(m_testDir->url());
179 QCOMPARE(props.viewMode(), DolphinView::Mode::DetailsView);
180 QVERIFY(props.hiddenFilesShown());
181 }
182
183 void ViewPropertiesTest::testParamMigrationToFileAttrKeepDirectory()
184 {
185 QString dotDirectoryFilePath = m_testDir->url().toLocalFile() + "/.directory";
186 QVERIFY(!QFile::exists(dotDirectoryFilePath));
187
188 const char *settingsContent = R"SETTINGS("
189 [Dolphin]
190 Version=4
191 ViewMode=1
192 Timestamp=2023,12,29,10,44,15.793
193 VisibleRoles=text,CustomizedDetails,Details_text,Details_modificationtime,Details_type
194
195 [Settings]
196 HiddenFilesShown=true
197
198 [Other]
199 ThoseShouldBeKept=true
200 )SETTINGS";
201 auto dotDirectoryFile = QFile(dotDirectoryFilePath);
202 QVERIFY(dotDirectoryFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate));
203 QTextStream out(&dotDirectoryFile);
204 out << settingsContent;
205 dotDirectoryFile.close();
206
207 KFileMetaData::UserMetaData metadata(m_testDir->url().toLocalFile());
208 {
209 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
210 QCOMPARE(props->viewMode(), DolphinView::Mode::DetailsView);
211 QVERIFY(props->hiddenFilesShown());
212 props->save();
213
214 if (metadata.isSupported()) {
215 auto viewProperties = metadata.attribute(QStringLiteral("kde.fm.viewproperties#1"));
216 QVERIFY(!viewProperties.isEmpty());
217 }
218
219 QVERIFY(QFile::exists(dotDirectoryFilePath));
220 KConfig directorySettings(dotDirectoryFilePath, KConfig::SimpleConfig);
221 QCOMPARE(directorySettings.groupList(), {"Other"});
222 }
223
224 ViewProperties props(m_testDir->url());
225 QVERIFY(props.hiddenFilesShown());
226 QCOMPARE(props.viewMode(), DolphinView::Mode::DetailsView);
227
228 QVERIFY(QFile::exists(dotDirectoryFilePath));
229 }
230
231 void ViewPropertiesTest::testExtendedAttributeFull()
232 {
233 #ifndef Q_OS_UNIX
234 QSKIP("Only unix is supported, for this test");
235 #endif
236 QString dotDirectoryFile = m_testDir->url().toLocalFile() + "/.directory";
237 QVERIFY(!QFile::exists(dotDirectoryFile));
238
239 KFileMetaData::UserMetaData metadata(m_testDir->url().toLocalFile());
240 if (!metadata.isSupported()) {
241 QSKIP("need extended attribute/filesystem metadata to be usefull");
242 }
243
244 QStorageInfo storageInfo(m_testDir->url().toLocalFile());
245 auto blockSize = storageInfo.blockSize();
246
247 KFileMetaData::UserMetaData::Error result;
248 // write a close to block size theorical maximum size for attributes in Linux for ext4
249 // and btrfs (4Kib typically) when ReiserFS/XFS allow XATTR_SIZE_MAX (64Kib)
250 result = metadata.setAttribute("data", QString(blockSize - 50, 'a'));
251 if (result != KFileMetaData::UserMetaData::NoSpace) {
252 QSKIP("File system supports metadata bigger than file system block size");
253 }
254
255 // write a close to 4k attribute, maximum size in Linux for ext4
256 // so next writing the file metadata fails
257 result = metadata.setAttribute("data", QString(blockSize - 60, 'a'));
258 QCOMPARE(result, KFileMetaData::UserMetaData::NoError);
259
260 QScopedPointer<ViewProperties> props(new ViewProperties(m_testDir->url()));
261 QVERIFY(props->isAutoSaveEnabled());
262 props->setSortRole("someNewSortRole");
263 props.reset();
264
265 if (metadata.isSupported()) {
266 auto viewProperties = metadata.attribute(QStringLiteral("kde.fm.viewproperties#1"));
267 QVERIFY(viewProperties.isEmpty());
268 QVERIFY(QFile::exists(dotDirectoryFile));
269
270 QFile dotDirectory(dotDirectoryFile);
271 KConfig viewSettings(dotDirectoryFile, KConfig::SimpleConfig);
272 QCOMPARE(viewSettings.groupList(), {"Dolphin"});
273 QCOMPARE(viewSettings.group("Dolphin").readEntry("SortRole"), "someNewSortRole");
274 } else {
275 QVERIFY(QFile::exists(dotDirectoryFile));
276 }
277 }
278
279 QTEST_GUILESS_MAIN(ViewPropertiesTest)
280
281 #include "viewpropertiestest.moc"