mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-30 14:54:13 +02:00
Merge pull request #1106 from ispyisail/feat/script-conductor-uuid
Add scripting calls to list wires by uuid and find their ends
This commit is contained in:
@@ -836,6 +836,18 @@ bool QetScriptApi::addConductor(int folioIndex,
|
||||
return t1->isLinkedTo(t2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// "{element uuid} terminal N", the form conductors() prints an end in and
|
||||
/// the conductor calls take as element uuid + terminal index.
|
||||
QString describeEnd(Terminal *t)
|
||||
{
|
||||
if (!t || !t->parentElement()) return QStringLiteral("?");
|
||||
return QStringLiteral("%1 terminal %2")
|
||||
.arg(t->parentElement()->uuid().toString())
|
||||
.arg(t->parentElement()->terminals().indexOf(t));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::conductors
|
||||
One line per conductor on the folio: which terminals it joins and its
|
||||
@@ -851,23 +863,57 @@ QStringList QetScriptApi::conductors(int folioIndex) const
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return list;
|
||||
|
||||
auto describe = [](Terminal *t) -> QString {
|
||||
if (!t || !t->parentElement()) return QStringLiteral("?");
|
||||
return QStringLiteral("%1 terminal %2")
|
||||
.arg(t->parentElement()->uuid().toString())
|
||||
.arg(t->parentElement()->terminals().indexOf(t));
|
||||
};
|
||||
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
const QList<Conductor *> all = content.conductors(DiagramContent::AnyConductor);
|
||||
for (Conductor *c : all)
|
||||
{
|
||||
list << QStringLiteral("%1 -- %2 : num='%3'")
|
||||
.arg(describe(c->terminal1), describe(c->terminal2), c->properties().text);
|
||||
.arg(describeEnd(c->terminal1), describeEnd(c->terminal2), c->properties().text);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::conductorUuids
|
||||
The uuid of every conductor on the folio, in the order conductors()
|
||||
lists them.
|
||||
*/
|
||||
QStringList QetScriptApi::conductorUuids(int folioIndex) const
|
||||
{
|
||||
QStringList list;
|
||||
if (!m_project) return list;
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return list;
|
||||
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
for (Conductor *c : content.conductors(DiagramContent::AnyConductor))
|
||||
list << c->uuid().toString();
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::conductorEnds
|
||||
The two ends of the conductor carrying @p uuid, each as
|
||||
"{element uuid} terminal N" -- the element uuid and terminal index the
|
||||
conductor calls take -- or an empty list if the folio has no such
|
||||
conductor. A uuid names one conductor even where two meet at a terminal,
|
||||
which an element uuid + terminal index cannot.
|
||||
*/
|
||||
QStringList QetScriptApi::conductorEnds(int folioIndex, const QString &uuid) const
|
||||
{
|
||||
if (!m_project) return {};
|
||||
const QList<Diagram *> diagrams = m_project->diagrams();
|
||||
if (folioIndex < 0 || folioIndex >= diagrams.count()) return {};
|
||||
const QUuid wanted(uuid);
|
||||
if (wanted.isNull()) return {};
|
||||
|
||||
DiagramContent content(diagrams.at(folioIndex), false);
|
||||
for (Conductor *c : content.conductors(DiagramContent::AnyConductor))
|
||||
if (c->uuid() == wanted)
|
||||
return {describeEnd(c->terminal1), describeEnd(c->terminal2)};
|
||||
return {};
|
||||
}
|
||||
|
||||
QString QetScriptApi::conductorProperty(int folioIndex, const QString &elementUuid,
|
||||
int terminalIndex, const QString &property) const
|
||||
{
|
||||
|
||||
@@ -396,6 +396,8 @@ class QetScriptApi : public QObject
|
||||
|
||||
// -- conductor properties, applied to the whole potential --
|
||||
Q_INVOKABLE QStringList conductors(int folioIndex) const;
|
||||
Q_INVOKABLE QStringList conductorUuids(int folioIndex) const;
|
||||
Q_INVOKABLE QStringList conductorEnds(int folioIndex, const QString &uuid) const;
|
||||
Q_INVOKABLE QString conductorProperty(int folioIndex, const QString &elementUuid,
|
||||
int terminalIndex, const QString &property) const;
|
||||
Q_INVOKABLE bool setConductorProperty(int folioIndex, const QString &elementUuid,
|
||||
|
||||
@@ -329,6 +329,22 @@ target_link_libraries(tst_conductorselfretrace PRIVATE Qt::Test)
|
||||
target_compile_definitions(tst_conductorselfretrace PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
|
||||
# qet.conductorUuids() / qet.conductorEnds(): a script lists a folio's
|
||||
# conductors by uuid and finds each one's two ends. Runs a script through
|
||||
# the real binary's --run on fixtures/qet_bug_repro_resaved.qet, so only
|
||||
# where --run exists: a build without the Qt Qml module has no scripting
|
||||
# (see QET_HAS_SCRIPTING in the top-level CMakeLists.txt).
|
||||
if(QET_HAS_SCRIPTING)
|
||||
add_executable(
|
||||
tst_scriptconductoruuid
|
||||
tst_scriptconductoruuid.cpp)
|
||||
add_test(NAME tst_scriptconductoruuid COMMAND tst_scriptconductoruuid)
|
||||
add_dependencies(tst_scriptconductoruuid qelectrotech)
|
||||
target_link_libraries(tst_scriptconductoruuid PRIVATE Qt::Test)
|
||||
target_compile_definitions(tst_scriptconductoruuid PRIVATE
|
||||
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
|
||||
endif()
|
||||
|
||||
# A symbol saved without a uuid gets the same one on every load, and
|
||||
# inserting a folio does not change it. Runs the real binary's --resave on
|
||||
# fixtures/qet_bug_repro_resaved.qet with the symbols' uuids stripped.
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <QtTest>
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QTemporaryDir>
|
||||
#include <QUuid>
|
||||
|
||||
// qet.conductorUuids(folio) and qet.conductorEnds(folio, uuid): a script can
|
||||
// list a folio's conductors by uuid and find where each one runs, in the
|
||||
// "{element} terminal N" form conductors() prints and the conductor calls
|
||||
// take. Runs a script through the real binary's --run.
|
||||
class tst_scriptconductoruuid : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTemporaryDir m_dir;
|
||||
|
||||
// Run @p script on the fixture in a sandbox of its own and return the
|
||||
// JSON object it logged.
|
||||
QJsonObject run(const QString &script)
|
||||
{
|
||||
const QString path = m_dir.filePath(QStringLiteral("probe.js"));
|
||||
const QString home = m_dir.filePath(QStringLiteral("home"));
|
||||
QDir().mkpath(home);
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::WriteOnly)) return {};
|
||||
f.write(script.toUtf8());
|
||||
f.close();
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
|
||||
env.insert(QStringLiteral("QET_ENABLE_SCRIPTING"), QStringLiteral("1"));
|
||||
env.insert(QStringLiteral("HOME"), home);
|
||||
env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config"));
|
||||
env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/data"));
|
||||
QProcess proc;
|
||||
proc.setProcessEnvironment(env);
|
||||
proc.start(QStringLiteral(QET_TEST_BINARY_PATH),
|
||||
{QStringLiteral("--run"), path,
|
||||
QFINDTESTDATA("fixtures/qet_bug_repro_resaved.qet")});
|
||||
if (!proc.waitForFinished(60000)) return {};
|
||||
const QString out = QString::fromUtf8(proc.readAllStandardOutput()
|
||||
+ proc.readAllStandardError());
|
||||
const QString mark = QStringLiteral("PROBE ");
|
||||
for (const QString &line : out.split(QLatin1Char('\n'))) {
|
||||
const int i = line.indexOf(mark);
|
||||
if (i >= 0)
|
||||
return QJsonDocument::fromJson(line.mid(i + mark.size()).toUtf8()).object();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QVERIFY(m_dir.isValid());
|
||||
QVERIFY(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)));
|
||||
}
|
||||
|
||||
void uuidsAndEndsMatchConductors()
|
||||
{
|
||||
const QJsonObject r = run(QStringLiteral(
|
||||
"var uuids = qet.conductorUuids(0);\n"
|
||||
"var ends = uuids.map(function (u) { return qet.conductorEnds(0, u); });\n"
|
||||
"qet.log('PROBE ' + JSON.stringify({lines: qet.conductors(0), uuids: uuids, ends: ends,\n"
|
||||
" unknown: qet.conductorEnds(0, '{00000000-0000-0000-0000-000000000001}'),\n"
|
||||
" junk: qet.conductorEnds(0, 'not a uuid'),\n"
|
||||
" badFolio: qet.conductorUuids(99)}));\n"));
|
||||
QVERIFY2(!r.isEmpty(), "the script logged nothing");
|
||||
|
||||
const QJsonArray lines = r.value(QStringLiteral("lines")).toArray();
|
||||
const QJsonArray uuids = r.value(QStringLiteral("uuids")).toArray();
|
||||
const QJsonArray ends = r.value(QStringLiteral("ends")).toArray();
|
||||
QCOMPARE(lines.size(), 7); // the fixture's conductors
|
||||
QCOMPARE(uuids.size(), lines.size());
|
||||
QSet<QString> distinct;
|
||||
for (int i = 0; i < uuids.size(); ++i) {
|
||||
const QString u = uuids.at(i).toString();
|
||||
QVERIFY2(!QUuid(u).isNull(), qPrintable(u));
|
||||
distinct.insert(u);
|
||||
// same order as conductors(), and the same two ends it prints
|
||||
const QJsonArray e = ends.at(i).toArray();
|
||||
QCOMPARE(e.size(), 2);
|
||||
const QString expected = e.at(0).toString() + QStringLiteral(" -- ")
|
||||
+ e.at(1).toString() + QStringLiteral(" : ");
|
||||
QVERIFY2(lines.at(i).toString().startsWith(expected),
|
||||
qPrintable(lines.at(i).toString() + QStringLiteral(" | ") + expected));
|
||||
}
|
||||
QCOMPARE(distinct.size(), uuids.size());
|
||||
|
||||
QVERIFY(r.value(QStringLiteral("unknown")).toArray().isEmpty());
|
||||
QVERIFY(r.value(QStringLiteral("junk")).toArray().isEmpty());
|
||||
QVERIFY(r.value(QStringLiteral("badFolio")).toArray().isEmpty());
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_scriptconductoruuid)
|
||||
|
||||
#include "tst_scriptconductoruuid.moc"
|
||||
Reference in New Issue
Block a user