- Rework the add/edit form onto a generic, catalog-driven field model (JobFieldCatalog + JobEditModel), replacing the old hand-written ApplicationEditDialog with ApplicationEditPage - Add a Preferences page (reachable from the hamburger menu) with a KColorSchemeManager-backed color scheme switcher - Add an About page reading from KAboutData - Ship a full hicolor icon set (16-128px + scalable) via ecm_install_icons instead of a single flat SVG - Restyle the edit form after KDE System Settings' Audio page: Kirigami.ListSectionHeader per category, flat separated rows, no card borders - Explicitly declare Kirigami/KirigamiAddons/ColorScheme as CMake dependencies instead of relying on the QML import scanner alone - Add KDEClangFormat/KDEGitCommitHooks, a CMakePresets.json, and a REUSE + clang-format lint CI workflow - Reformat SPDX headers to include copyright, remove debug screenshot scaffolding
151 lines
4.4 KiB
C++
151 lines
4.4 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2026 ToServeTheKing <[email protected]>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "job.h"
|
|
#include "jobsdatabase.h"
|
|
|
|
#include <QTemporaryDir>
|
|
#include <QtTest>
|
|
|
|
namespace
|
|
{
|
|
QString dbPathIn(const QTemporaryDir &dir)
|
|
{
|
|
return dir.path() + QStringLiteral("/test.sqlite");
|
|
}
|
|
}
|
|
|
|
class JobsDatabaseTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
void addAndRetrieve()
|
|
{
|
|
QTemporaryDir dir;
|
|
QVERIFY(dir.isValid());
|
|
JobsDatabase db(dbPathIn(dir));
|
|
QVERIFY(db.isOpen());
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("Acme Corp");
|
|
job.title = QStringLiteral("Software Engineer");
|
|
job.dateApplied = QDate(2026, 6, 1);
|
|
job.salaryMin = 120000;
|
|
job.salaryMax = 150000;
|
|
|
|
QVERIFY(db.addJob(job));
|
|
QVERIFY(job.id > 0);
|
|
QCOMPARE(job.stage, QStringLiteral("Applied"));
|
|
QVERIFY(job.createdAt.isValid());
|
|
|
|
const auto fetched = db.jobById(job.id);
|
|
QVERIFY(fetched.has_value());
|
|
QCOMPARE(fetched->company, QStringLiteral("Acme Corp"));
|
|
QCOMPARE(fetched->salaryMin, 120000);
|
|
QCOMPARE(fetched->salaryMax, 150000);
|
|
QCOMPARE(fetched->stage, QStringLiteral("Applied"));
|
|
|
|
const auto transitions = db.stageTransitions();
|
|
QCOMPARE(transitions.size(), 1);
|
|
QVERIFY(transitions.first().fromStage.isEmpty());
|
|
QCOMPARE(transitions.first().toStage, QStringLiteral("Applied"));
|
|
}
|
|
|
|
void rejectsUnknownStage()
|
|
{
|
|
QTemporaryDir dir;
|
|
JobsDatabase db(dbPathIn(dir));
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("Acme");
|
|
job.title = QStringLiteral("Engineer");
|
|
job.stage = QStringLiteral("Bogus");
|
|
|
|
QVERIFY(!db.addJob(job));
|
|
QVERIFY(!db.lastError().isEmpty());
|
|
}
|
|
|
|
void updateJobDoesNotTouchStage()
|
|
{
|
|
QTemporaryDir dir;
|
|
JobsDatabase db(dbPathIn(dir));
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("A");
|
|
job.title = QStringLiteral("B");
|
|
QVERIFY(db.addJob(job));
|
|
|
|
Job edited = *db.jobById(job.id);
|
|
edited.company = QStringLiteral("Updated Co");
|
|
edited.stage = QStringLiteral("Rejected"); // updateJob must ignore this
|
|
QVERIFY(db.updateJob(edited));
|
|
|
|
const auto fetched = db.jobById(job.id);
|
|
QCOMPARE(fetched->company, QStringLiteral("Updated Co"));
|
|
QCOMPARE(fetched->stage, QStringLiteral("Applied"));
|
|
}
|
|
|
|
void stageTransitionsRecordHistory()
|
|
{
|
|
QTemporaryDir dir;
|
|
JobsDatabase db(dbPathIn(dir));
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("A");
|
|
job.title = QStringLiteral("B");
|
|
QVERIFY(db.addJob(job));
|
|
|
|
QVERIFY(db.setStage(job.id, QStringLiteral("Screening")));
|
|
QVERIFY(db.setStage(job.id, QStringLiteral("Screening"))); // no-op: same stage
|
|
QVERIFY(db.setStage(job.id, QStringLiteral("Rejected")));
|
|
|
|
const auto transitions = db.stageTransitions();
|
|
// Start->Applied, Applied->Screening, Screening->Rejected (the no-op adds nothing)
|
|
QCOMPARE(transitions.size(), 3);
|
|
QCOMPARE(transitions.at(1).fromStage, QStringLiteral("Applied"));
|
|
QCOMPARE(transitions.at(1).toStage, QStringLiteral("Screening"));
|
|
QCOMPARE(transitions.at(2).fromStage, QStringLiteral("Screening"));
|
|
QCOMPARE(transitions.at(2).toStage, QStringLiteral("Rejected"));
|
|
|
|
const auto fetched = db.jobById(job.id);
|
|
QCOMPARE(fetched->stage, QStringLiteral("Rejected"));
|
|
}
|
|
|
|
void setStageRejectsUnknownStage()
|
|
{
|
|
QTemporaryDir dir;
|
|
JobsDatabase db(dbPathIn(dir));
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("A");
|
|
job.title = QStringLiteral("B");
|
|
QVERIFY(db.addJob(job));
|
|
|
|
QVERIFY(!db.setStage(job.id, QStringLiteral("Bogus")));
|
|
QCOMPARE(db.jobById(job.id)->stage, QStringLiteral("Applied"));
|
|
}
|
|
|
|
void deleteCascadesHistory()
|
|
{
|
|
QTemporaryDir dir;
|
|
JobsDatabase db(dbPathIn(dir));
|
|
|
|
Job job;
|
|
job.company = QStringLiteral("A");
|
|
job.title = QStringLiteral("B");
|
|
QVERIFY(db.addJob(job));
|
|
QVERIFY(db.setStage(job.id, QStringLiteral("Screening")));
|
|
|
|
QVERIFY(db.deleteJob(job.id));
|
|
QVERIFY(!db.jobById(job.id).has_value());
|
|
QVERIFY(db.stageTransitions().isEmpty());
|
|
}
|
|
};
|
|
|
|
QTEST_GUILESS_MAIN(JobsDatabaseTest)
|
|
#include "jobsdatabasetest.moc"
|