mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-05 18:54:14 +02:00
8434b88eb8
Since #849 the parts list has a row for every contact block (slave) and terminal-type element. Users who draw the dots and bends where wires branch as terminal-type symbols (114_connections) get one empty row per junction: 109 of 151 rows on one reported cabinet. Two options, both off by default so existing exports are unchanged: - leave out the contact blocks: --no-slaves, "no_slaves" in qet_export, or uncheck the new "Contacts esclaves" element type in the dialog; - leave out the junctions: terminal-type elements with no label, designation, manufacturer or manufacturer reference. --no-junctions, "no_junctions", or "Laisser de côté les jonctions" in the dialog. A terminal block with a label or a part number stays. The element type filter had no box for slaves, so every query it built left them out: the export dialog never listed contact blocks, although the command line has since #849. The dialog now checks the new box by default and gives the same rows as --export-bom. The box is unchecked by default elsewhere, so nomenclature tables keep their rows. docs/smart-device-bom.md still said slaves and terminals were excluded; corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
174 lines
6.5 KiB
C++
174 lines
6.5 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "bomexport.h"
|
|
|
|
#include <QFile>
|
|
#include <QSqlDatabase>
|
|
#include <QSqlError>
|
|
#include <QSqlQuery>
|
|
#include <QTemporaryDir>
|
|
#include <QtTest>
|
|
|
|
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"));
|
|
|
|
//#1178: a junction -- a terminal-type symbol drawn where wires
|
|
//branch -- has no label and no part data. It can be left out, and
|
|
//so can the contact blocks; a terminal block with only a part
|
|
//number stays.
|
|
QSqlQuery raw(db);
|
|
QVERIFY(raw.exec(QStringLiteral(
|
|
"INSERT INTO element_nomenclature_view "
|
|
"(label, element_type, diagram_position, position) "
|
|
"VALUES (NULL, 'terminal', 1, 6)")));
|
|
QVERIFY(raw.exec(QStringLiteral(
|
|
"INSERT INTO element_nomenclature_view "
|
|
"(label, designation, manufacturer, manufacturer_reference, "
|
|
"element_type, diagram_position, position) "
|
|
"VALUES ('', '', '', 'PT 2,5', 'terminal', 1, 7)")));
|
|
auto count = [&db](const QString &sql) {
|
|
QSqlQuery q(db);
|
|
if (!q.exec(sql))
|
|
return -1;
|
|
int n = 0;
|
|
while (q.next())
|
|
++n;
|
|
return n;
|
|
};
|
|
QCOMPARE(count(BomExport::defaultQuery()), 6);
|
|
QCOMPARE(count(BomExport::defaultQuery(true, false)), 5);
|
|
QCOMPARE(count(BomExport::defaultQuery(false, true)), 5);
|
|
QCOMPARE(count(BomExport::defaultQuery(false, false)), 4);
|
|
}
|
|
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"
|