/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see .
*/
#include "bomexport.h"
#include
#include
#include
#include
#include
#include
class SmartDeviceTest : public QObject
{
Q_OBJECT
private slots:
void metadataColumns();
void defaultQueryAndCsv();
void atomicWrite();
};
void SmartDeviceTest::metadataColumns()
{
const auto columns = BomExport::defaultColumns();
for (const QString &column : {
QStringLiteral("label"), QStringLiteral("manufacturer"),
QStringLiteral("manufacturer_reference"), QStringLiteral("model"),
QStringLiteral("description"), QStringLiteral("category"),
QStringLiteral("quantity"), QStringLiteral("voltage_rating"),
QStringLiteral("current_rating"), QStringLiteral("folio"),
QStringLiteral("notes")})
{
QVERIFY2(columns.contains(column), qPrintable(column));
}
}
void SmartDeviceTest::defaultQueryAndCsv()
{
const QString connection = QStringLiteral("smart-device-%1")
.arg(QUuid::createUuid().toString());
{
auto db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), connection);
db.setDatabaseName(QStringLiteral(":memory:"));
QVERIFY2(db.open(), qPrintable(db.lastError().text()));
QSqlQuery setup(db);
QVERIFY(setup.exec(QStringLiteral(
"CREATE TABLE element_nomenclature_view ("
"label TEXT, designation TEXT, manufacturer TEXT, "
"manufacturer_reference TEXT, model TEXT, description TEXT, "
"category TEXT, quantity TEXT, voltage_rating TEXT, "
"current_rating TEXT, folio TEXT, notes TEXT, "
"element_type TEXT, diagram_position INTEGER, position INTEGER)")));
QSqlQuery insert(db);
insert.prepare(QStringLiteral(
"INSERT INTO element_nomenclature_view VALUES "
"(?, '', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
auto add = [&insert](const QString &tag, const QString &type, int page,
int position, const QString &manufacturer) {
insert.bindValue(0, tag);
insert.bindValue(1, manufacturer);
insert.bindValue(2, QStringLiteral("0012"));
insert.bindValue(3, QStringLiteral("M-1"));
insert.bindValue(4, QStringLiteral("Power contactor"));
insert.bindValue(5, QStringLiteral("Control"));
insert.bindValue(6, QStringLiteral("1"));
insert.bindValue(7, QStringLiteral("24 V DC"));
insert.bindValue(8, QStringLiteral("16 A"));
insert.bindValue(9, QString::number(page));
insert.bindValue(10, QStringLiteral("Quoted \"note\"\nnext line"));
insert.bindValue(11, type);
insert.bindValue(12, page);
insert.bindValue(13, position);
return insert.exec();
};
QVERIFY(add(QStringLiteral("-K2"), QStringLiteral("simple"), 2, 1,
QStringLiteral("日本電機")));
QVERIFY(add(QStringLiteral("-K1"), QStringLiteral("master"), 1, 2,
QStringLiteral("Müller")));
//A slave and a terminal are both separately orderable hardware -- an
//auxiliary contact block has its own order code, and so does a
//terminal block -- so both belong in the bill of materials. See
//discussion #847. Anything that should not be ordered is kept out by
//exclude_from_bom rather than by its base type.
QVERIFY(add(QStringLiteral("-K1.1"), QStringLiteral("slave"), 1, 3,
QStringLiteral("Aux contact block")));
QVERIFY(add(QStringLiteral("X1"), QStringLiteral("terminal"), 1, 4,
QStringLiteral("Terminal block")));
//Still filtered out: a folio report arrow is not hardware.
QVERIFY(add(QStringLiteral(">1"), QStringLiteral("next_report"), 1, 5,
QStringLiteral("Must not be exported")));
QSqlQuery query(db);
QVERIFY2(query.exec(BomExport::defaultQuery()),
qPrintable(query.lastError().text()));
int rows = 0;
const auto csv = BomExport::toCsv(
query, BomExport::defaultColumns(), true, &rows);
QCOMPARE(rows, 4);
QVERIFY(csv.startsWith("\xEF\xBB\xBF\"label\";\"designation\";"));
QVERIFY(csv.contains(QStringLiteral("Müller").toUtf8()));
QVERIFY(csv.contains(QStringLiteral("日本電機").toUtf8()));
QVERIFY(csv.contains("\"Quoted \"\"note\"\"\nnext line\""));
QVERIFY(csv.contains("Aux contact block"));
QVERIFY(csv.contains("Terminal block"));
QVERIFY(!csv.contains("Must not be exported"));
QVERIFY(csv.indexOf("-K1") < csv.indexOf("-K2"));
}
QSqlDatabase::removeDatabase(connection);
}
void SmartDeviceTest::atomicWrite()
{
QTemporaryDir temporary;
QVERIFY(temporary.isValid());
const auto path = temporary.filePath(QStringLiteral("bom.csv"));
const QByteArray csv("\xEF\xBB\xBF\"label\"\n");
QString error = QStringLiteral("stale");
QVERIFY(BomExport::writeCsv(path, csv, &error));
QVERIFY(error.isEmpty());
QFile file(path);
QVERIFY(file.open(QIODevice::ReadOnly));
QCOMPARE(file.readAll(), csv);
QVERIFY(!BomExport::writeCsv(
temporary.filePath(QStringLiteral("missing/bom.csv")), csv, &error));
QVERIFY(!error.isEmpty());
}
QTEST_GUILESS_MAIN(SmartDeviceTest)
#include "tst_smart_device.moc"