ssu
upgradetesthelper.cpp
Go to the documentation of this file.
1 
8 #include "upgradetesthelper.h"
9 
10 #include <QtCore/QBuffer>
11 #include <QtCore/QDebug>
12 #include <QtCore/qmath.h>
13 #include <QtCore/QTemporaryFile>
14 #include <QtCore/QTextStream>
15 
16 #include "libssu/ssusettings_p.h"
17 
90 QList<UpgradeTestHelper::TestCase> UpgradeTestHelper::readRecipe(QIODevice *recipe)
91 {
92  QList<TestCase> testCases;
93 
94  while (!recipe->atEnd()) {
95  const QString line = recipe->readLine().trimmed();
96  if (line.startsWith('#') || line.isEmpty())
97  continue;
98  const QStringList splitted = line.split(':');
99  Q_ASSERT_X(splitted.count() == 3, Q_FUNC_INFO,
100  qPrintable(QString("Inalid recipe line '%1'").arg(line)));
101  testCases.append(TestCase(splitted.at(0), splitted.at(1), splitted.at(2)));
102  }
103 
104  return testCases;
105 }
106 
107 void UpgradeTestHelper::fillSettings(QSettings *settings, const QList<TestCase> &testCases)
108 {
109  settings->setValue("configVersion", CurrentVersion);
110 
111  foreach (const QString &group, groups()) {
112  settings->beginGroup(group);
113 
114  foreach (const TestCase &testCase, testCases) {
115  if (!testCase.current().isEmpty()) {
116  settings->setValue(testCase.key(), testCase.current());
117  }
118  }
119 
120  settings->endGroup();
121  }
122 
123  settings->sync();
124 }
125 
126 void UpgradeTestHelper::fillDefaultSettings(QSettings *defaultSettings, const QList<TestCase>
127  &testCases)
128 {
129  defaultSettings->setValue("configVersion", HistoryLength);
130 
131  QHash<QString, QString> lastSetValue; // for the (K)eep action; no need to qualify with group
132 
133  for (int revision = 1; revision <= HistoryLength; ++revision) {
134  defaultSettings->beginGroup(QString::number(revision));
135 
136  QStringList keysToRemove;
137 
138  foreach (const QString &group, groups()) {
139  defaultSettings->beginGroup(group);
140 
141  foreach (const TestCase &testCase, testCases) {
142  switch (testCase.history().at(revision - 1).toLatin1()) {
143  case 'S': // (S)et value
144  lastSetValue[testCase.key()] = QString("v%1-default").arg(revision);
145  defaultSettings->setValue(testCase.key(), lastSetValue[testCase.key()]);
146  break;
147 
148  case 'K': // (K)eep value
149  Q_ASSERT_X(!lastSetValue[testCase.key()].isEmpty(), Q_FUNC_INFO,
150  qPrintable(QString("Inalid TestCase::history: '%1'").arg(testCase.history())));
151  defaultSettings->setValue(testCase.key(), lastSetValue[testCase.key()]);
152  break;
153 
154  case 'R': // (R)emove key
155  keysToRemove.append((group.isEmpty() ? group : group + "/") + testCase.key());
156  lastSetValue.remove(testCase.key());
157  break;
158 
159  case 'N': // (N)oop
160  break;
161 
162  default:
163  Q_ASSERT_X(false, Q_FUNC_INFO, qPrintable(QString(
164  "Inalid TestCase::history: '%1': invalid command-code '%2'")
165  .arg(testCase.history())
166  .arg(testCase.history().at(revision - 1))));
167  }
168 
169  }
170 
171  defaultSettings->endGroup();
172  }
173 
174  if (!keysToRemove.isEmpty()) {
175  defaultSettings->setValue("cmd-remove", keysToRemove);
176  }
177 
178  defaultSettings->endGroup();
179  }
180 
181  defaultSettings->sync();
182 }
183 
184 bool UpgradeTestHelper::generateSnapshotRecipe(QTextStream *out)
185 {
186  const QString actions = "SKRN";
187 
188  QBuffer buf;
189  buf.open(QIODevice::ReadWrite);
190  QTextStream stream(&buf);
191 
192  // for all "valid" variations of the letters "SKRN" of length HistoryLength
193  for (int i = 0; i < qPow(actions.count(), HistoryLength); ++i) {
194  QString history = QString::number(i, actions.count());
195  // Left pad to HistoryLength
196  history.prepend(QString(HistoryLength - history.length(), '0'));
197  for (int revision = 0; revision < history.length(); ++revision) {
198  history.replace(revision, 1, actions.at(history.at(revision).digitValue()));
199  }
200 
201  static const QRegExp invalidSequence("(^[^S]*K|R[^S]*K|^R)");
202  if (history.contains(invalidSequence)) {
203  continue;
204  }
205 
206  for (int revision = 0; revision < HistoryLength; ++revision) {
207  stream << history << QString(":v%1-default:\n").arg(revision);
208  }
209 
210  stream << history << ":custom:\n";
211  }
212 
213  stream.flush();
214 
215  // Read recipe
216  buf.seek(0);
217  QList<TestCase> testCases = readRecipe(&buf);
218 
219  // Generate settings file according to recipe
220  QTemporaryFile settingsFile;
221  if (!settingsFile.open()) {
222  return false;
223  }
224 
225  QSettings settings(settingsFile.fileName(), QSettings::IniFormat);
226 
227  fillSettings(&settings, testCases);
228 
229  // Generate defaults file according to recipe
230  QTemporaryFile defaultSettingsFile;
231  if (!defaultSettingsFile.open()) {
232  return false;
233  }
234 
235  QSettings defaultSettings(defaultSettingsFile.fileName(), QSettings::IniFormat);
236 
237  fillDefaultSettings(&defaultSettings, testCases);
238 
239  // Parse settings -- do upgrade
240  SsuSettings ssuSettings(settingsFile.fileName(), QSettings::IniFormat,
241  defaultSettingsFile.fileName());
242 
243  // Output recipe
244  foreach (const UpgradeTestHelper::TestCase &testCase, testCases) {
245  const QString expected = ssuSettings.contains(testCase.key())
246  ? ssuSettings.value(testCase.key()).toString()
247  : "@NOTSET@";
248  *out << QString("%1:%2:%3\n")
249  .arg(testCase.history())
250  .arg(testCase.current())
251  .arg(expected);
252  }
253 
254  return true;
255 }
256 
257 QStringList UpgradeTestHelper::groups()
258 {
259  static const QStringList groups = QStringList() << "" /* General */ << "groupA";
260  return groups;
261 }
SsuSettings
Definition: ssusettings_p.h:30
UpgradeTestHelper::TestCase
Definition: upgradetesthelper.h:33
upgradetesthelper.h
ssusettings_p.h