Commit Graph

32 Commits

Author SHA1 Message Date
ispyisail 2ed85f6fc7 Address review: qRound-consistent guards, regression test
Addresses scorpio810's review of PR #890 (bugtracker #734):

- The four cas "3"/"4" bridge-skip guards now compare qRound()ed
  coordinates, matching how the bridge coordinate itself is computed --
  an exact != would miss a pair already grid-equal after rounding but
  off by a sub-pixel remainder, and still route a degenerate bridge for
  it. Verified no behavior change on the shipped corpus: per-file
  self-retrace counts are identical before/after (every coordinate
  there already lands exactly on-grid).
- Added tests/qttest/tst_conductorselfretrace.cpp, fixture
  qet_bug_repro_resaved.qet (the report's own canonical reproduction):
  exports it via the built binary's --export-svg and asserts no
  conductor path is self-retracing. Confirmed it actually catches the
  regression, not just passes vacuously -- reverted conductor.cpp to
  master and reran: fails, 1 self-retracing path found.

Not changed in code: the cas "4" descending-branch dead-code note (kept
for symmetry, as already agreed) and the schema_unifilaire_voltaique2.qet
trade-off (flagged for the reviewer's own visual check).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 05:08:14 +12:00
Laurent Trinques 607eb4b1ea Merge pull request #871 from ispyisail/test/ipc-open-forwarding-regression
Add a regression test for the forwarded-file use-after-free
2026-09-15 09:55:34 +02:00
ispyisail bd6bed8d61 Open the menu bar on F10, and add a test that can answer whether it works
F10 opens the menu bar in most applications and is the usual way to reach
the menus without a mouse. Qt provides this on Windows but not on X11, so on
Linux the key did nothing and the press fell through to whichever widget had
focus. It matters more here than it might elsewhere: "&Édition" takes É for
its own letter, which is not on a UK or US keyboard, so that menu has no
direct Alt route at all.

A window-context QShortcut rather than a key handler -- key presses go to
the focused child widget, so a keyPressEvent() on the window would never see
F10 while the canvas or a panel has focus.

tests/qttest/tst_menubarkeyboard.cpp covers three things: that Alt and a
letter opens a menu (the control), that plain F10 does nothing in Qt itself
(which is why the shortcut exists, and which will fail loudly if a future Qt
starts handling it), and that the shortcut mechanism opens the bar.

It uses QTest instead of driving a real X server for a specific reason.
xdotool on Xvfb delivers every function key with Alt held: a Qt key logger
shows Key_F10 arriving with modifiers == Qt::AltModifier. --clearmodifiers,
keydown/keyup pairs, --window targeting and flattening the keycode with
xmodmap all made no difference. Two rounds of GUI automation therefore gave
confident, wrong answers about F10 -- first that it was broken, then that
this very fix did not work. QTest posts the event straight to the widget, so
the key arrives as written.

What the test does not cover, since initCommonActions() calls
QETApp::instance() and constructing that pulls in the whole application: it
repeats the wiring rather than driving QETMainWindow. Confirming the real
window responds still needs someone to press F10 in a running QElectroTech.

Verified by breaking it: bound to F11 instead, the test fails. Qt 5 and Qt 6
both build clean, 6/6 tests on each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:44:59 +12:00
ispyisail 9363e9bc2e Add a regression test for the forwarded-file use-after-free
Covers the crash fixed in #868: a file forwarded from a second instance was
opened inside SingleApplication's socket handler, so the backup prompt's
nested event loop ran while that handler was still on the stack.

Run by hand; no build system or CI changes.

    tests/ipc-regression/run.sh --binary build/qelectrotech

Validated in both directions on Qt 6.10.2: ceda1e082 (before the fix) crashes
3 times in 3 with exit 139, 199444b6 (after) survives 3 times in 3.

Three requirements are not obvious and are documented in the script:

- Qt 6 only. An unfixed Qt 5 build survives every attempt, so the script
  refuses to run on a Qt 5 binary rather than report a pass that cannot fail.
- A Debug build. The same unfixed commit survives every attempt built
  -O3 -DNDEBUG; whether a use-after-free faults depends on what the allocator
  does with the freed block.
- Dismissing the backup prompt is the step that triggers it. Left open, the
  stack never unwinds and nothing fails, which is why the bug was twice
  reported as not reproducible.

The test runs in its own sandbox on its own X display, works on a copy of the
project so backup files do not land in examples/, and cleans up after itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 07:09:16 +12:00
ispyisail fcd2a4e0e0 Fix bugtracker #248: opening a file while QET is running does nothing
QET::splitWithSpaces() split on QRegularExpression("[^\\]?(?:\\\\)* ").
That is not a valid pattern: "[^\\]" opens a character class whose "\\]" is
an escaped bracket, so the class is never closed. QRegularExpression
reported isValid() == false, QString::split() warned "invalid
QRegularExpression object", and the function returned an EMPTY list for
every input.

It is the receiving half of the SingleApplication handshake: a secondary
instance sends "launched-with-args: " + joinWithSpaces(args) (main.cpp) and
the running instance parses it in QETApp::receiveMessage() before calling
openFiles(). With the split always empty, the running instance received no
arguments at all -- so opening a project while QET was already running
silently did nothing.

The bug is reported against filenames containing spaces, which is how it
was noticed, but it is not limited to them: plain names failed identically.

A corrected regex is not available. The separator is a space preceded by an
even-length run of backslashes, and PCRE2 has no variable-length lookbehind,
so the run cannot be expressed in a lookbehind and anything that matches it
by consumption eats the character before the space -- which is what the
"[^\\]?" was for. Scanning the string explicitly is correct and easier to
read.

tests/qttest/tst_qetstrings.cpp asserts the round trip
splitWithSpaces(joinWithSpaces(x)) == x over plain names, embedded spaces,
embedded backslashes, a trailing backslash and a mixture, plus the specific
regression that a plain argument list does not come back empty.

Verified the test fails without the fix: 9 of 11 cases fail on the old
implementation and all 11 pass with it. Full suite 5/5, Qt 5.15.18.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 14:55:17 +12:00
ispyisail b034d3c5b3 Include slave and terminal elements in the bill of materials
A slave and a terminal are both routinely separately orderable hardware. A
circuit breaker can carry ten or twenty auxiliary blocks, each with its own
order code, and a terminal block is a purchased part in its own right.
Neither was reaching the bill of materials.

Decided in discussion #847: @IBSYSLevi -- "I would not expect that a defined
piece of hardware is excluded from BOM when not specifically defined as so" --
with use cases from @jozi332 covering Siemens breakers with ten to twenty
auxiliary blocks and PLC cards carrying per-channel data.

Two filters had to change, which is easy to miss: BomExport::defaultQuery()
and, upstream of it, the WHERE clause of element_nomenclature_view itself.
Changing only the query does nothing for slaves, because the view had already
removed them. Terminals were already in the view, so they appeared as soon as
the query allowed them -- which made a half-finished change look like it had
worked.

Measured on examples/industrial.qet, which holds 96 terminals and 41 slaves:
258 rows before, 354 with terminals, 395 with both. A slave given a
manufacturer and part number now appears in the export; previously it could
not, at any setting.

Nothing that should stay out of a bill of materials is newly included. The
folio report arrows and the conductor definition are still excluded because
they are not hardware, and anything else -- a relay's own auxiliary contact,
which is not orderable separately -- is kept out with exclude_from_bom, which
the view already honours and which #721 and #765 made settable on the symbol
itself.

tst_smart_device is updated rather than weakened. @enesgursoy6110 wrote it in
#830 to prove the filter works, inserting rows designated "Must not be
exported"; the slave and terminal rows now carry real designations and are
asserted present, and a folio report arrow takes over as the negative case,
so the test still proves filtering happens -- at the boundary we now want.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 02:00:50 +12:00
Andre Rummler 4e9463ee8a Do not install PugiXML and Googletest static libraries. These are only needed during compile time. 2026-09-12 12:02:55 +02:00
enesgursoy6110 77f8e26ffc Address smart device BOM review feedback 2026-09-11 20:12:09 +03:00
enesgursoy6110 16dbc5c404 Add ungrouped device BOM CSV export 2026-09-11 20:11:28 +03:00
ispyisail 6f2c66afef Show used against declared capacity where a master declares contact groups
Second half of #819: where a coil declares what contacts it provides, the
General tab now reports each type as used against declared rather than as
a bare count.

    NO : 3/4, NC : 1/2, inverseurs : 0/1, autres : 0/0

MasterElement::contactCapacity() sums contactCount over the element's
SlaveContactGroup list, per type, reusing the same ContactUsage tally the
used count is built on. The mapping from ElementData::SlaveState onto the
tally's own type is factored into one helper so the used count and the
declared capacity cannot classify a contact differently.

Falls back to the plain count from the previous commit when an element
declares no groups, which is every element in the standard collection
today -- nothing in the corpus declares slaveContactGroups, so this
changes no existing display.

A type used beyond what is declared reads as e.g. "1/0". That is
deliberate: it says this contact does not fit the part.

Display only. Whether a declared capacity should also feed
MasterElement::isFull() is the open question in #819 and is not touched
here.

Verified end to end against a purpose-built fixture, since no existing
element exercises this path: a coil declaring two NO groups of two, one
NC group of two and one changeover group of one parses and reports
NO=4 NC=2 SW=1 other=0 total=7, matching the declaration exactly.
tst_contactusage gains a case covering capacity summed across groups
(10 cases, all passing).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:49:16 +12:00
ispyisail c33f250910 Count master contacts in one place, and count contacts not elements
MasterElement::isFull() decided whether a coil had room left with

    connected_elements.size() >= max_slaves

which counts linked *elements*. A slave stands for as many contacts as
its "number" kind information declares, so a 4 pole contact consumed a
single contact from the coil's budget instead of four. 36 elements in
the standard collection declare a number between 2 and 4, so this is
reachable, not theoretical.

Add ContactUsage, a header-only tally holding the two rules that are
easy to get wrong:

 - a slave counts once per contact it declares, not once per element
 - a changeover is counted once, as sw, and never as one NO plus one
   NC. CrossRefItem::NOElements() and NCElements() both return
   changeovers, so a count built by adding those two lists together
   reports one changeover as two contacts.

The upcoming per-type displays (the used count in the element's General
tab, and the per-type budget on the cross reference) need exactly this
count, so it lives in one place rather than being written out three
times, and isFull() now reads it too.

The header carries no graphics dependency, so the counting rules are
unit tested on their own in tests/qttest/tst_contactusage.cpp,
following the same pattern as diagramsortkeys.h.

Verified: all 9 unit tests pass, and both rules were mutation checked
(counting elements instead of contacts fails 2 tests, counting a
changeover as both NO and NC fails 3). The 23 example projects still
load and export without crash or hang, and qet-lint reports no
regressions against its baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:08:00 +12:00
ispyisail bd5cff4211 Add a unit test locking in Diagram::toXml()'s coordinate sort order
Follow-up to the positionKey() fix merged directly in #779
(b2f4ef5d2): per review request, add a small regression test so this
class of bug (fixed-precision "%.4f" formatting compares out of
numeric order once the integer part's digit count differs) can't
silently reappear.

positionKey()/coordinateKey() move out of diagram.cpp's anonymous
namespace into a small header-only diagramsortkeys.h so the test can
link against the exact same code Diagram::toXml() uses, instead of
duplicating the algorithm. Behavior is unchanged.

tst_diagramsortkeys covers: single- vs double-digit, double- vs
triple-digit, negative-vs-negative, negative-vs-positive, and
negative-vs-zero coordinate pairs, plus sub-precision deltas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 20:54:18 +12:00
Andre Rummler c14d6a6dd6 In order to migrate to Qt6 all options for KF6 were added:
a) using a system provided KF6
b) downloading and compiling KF6
c) using the vendored-in re-creation of the functionality

The behaviour for both Qt5 and Qt6 is steered with the same two variables which were renamed to become version agnostic:
a) BUILD_WITH_KF=ON BUILD_KF=OFF
b) BUILD_WITH_KF=ON BUILD_KF=ON
c) BUILD_WITH_KF=OFF

The version is automatically derived from the chosen Qt major version.
2026-08-12 12:29:56 +02:00
Dieter Mayer 683eefdac1 Request the GuiPrivate component only on Qt6
Listing GuiPrivate unconditionally in QET_COMPONENTS breaks the whole
Qt5 configure: find_package(Qt5 COMPONENTS GuiPrivate) looks for a
Qt5GuiPrivateConfig.cmake that has never existed - Qt5 creates the
Qt5::GuiPrivate target implicitly together with Gui. Only Qt6 requires
(and provides) the explicit component.

Move the request into a QT_VERSION_MAJOR-guarded find_package after the
main one, both for the application and for tests/catch (whose targets
link Qt::GuiPrivate via QET_PRIVATE_LIBRARIES). Fixes the msys2/Qt5
Windows CI configure failure:
"Could not find a package configuration file provided by Qt5GuiPrivate".

Verified: Qt 6.11 configure passes and the Qt6::GuiPrivate target is
created (the private-module warning now fires from the guarded call).
The Qt5 path simply no longer requests the component, restoring the
pre-existing implicit behaviour.
2026-07-17 19:25:26 +02:00
Gerhard Schwanzer dcec0bf7ff Skip actively locked autosave files
Check the QLockFile in staleFiles() before returning a no-KF5 recovery candidate, matching the KAutoSaveFile contract that actively owned autosave files are not stale.

Extend the no-KF5 Catch test so a child process keeps the autosave lock alive while allStaleFiles() runs, then verify recovery after the child is killed.

Assisted-by: pi coding agent / Mika (OpenAI GPT-5.5)
2026-07-05 17:39:38 +02:00
Gerhard Schwanzer 7a97e873d9 Test Qt-only autosave recovery fallback
Add a no-KF5 Catch regression test that leaves a KAutoSaveFile-compatible backup behind from a child process, then verifies stale-file discovery, stale-lock recovery, reading, and cleanup.

Assisted-by: pi coding agent / Mika (OpenAI GPT-5.5)
2026-07-05 15:52:25 +02:00
Andre Rummler ea9d57cdde Update googltest library to v1.17.0 2025-09-08 13:27:56 +02:00
Andre Rummler bad60834cc Update Catch2 library to v2.13.10 2025-09-08 13:26:54 +02:00
plc-user b3ac3c82af fixed indentations of the remaining *.cpp/*.h files 2024-05-02 08:39:27 +02:00
luz paz 2032ba76ed Fix various typos in source documentation and comments (cont.)
Found via `codespell`
2022-12-06 07:56:45 +01:00
Simon De Backer cb37c1c2fe Add switch for KF5 (QT6) and Mod Cmake
if we want to test QET on QT6, KF5 must be removed from the code,
this switch is for that,

this is for testing only
2020-12-16 23:06:08 +01:00
Simon De Backer c88d1ef6bb Refactoring Cmake
cleaning up the Cmake code
2020-12-13 00:40:43 +01:00
Simon De Backer d2fb0d8ad1 Fix stop the run autotests of kcoreaddons
see
https://invent.kde.org/frameworks/kcoreaddons/-/blob/master/CMakeLists.txt#L98

issue:
CMake Error at /usr/share/ECM/modules/ECMAddTests.cmake:89 (add_executable):
  Cannot find source file:
see
https://qelectrotech.org/forum/viewtopic.php?pid=13929#p13929
2020-12-11 23:57:17 +01:00
Simon De Backer 83d802adf7 Mod Cmake first working build 2020-12-11 14:55:11 +01:00
Simon De Backer ed938c82cd Mod Cmake 2020-12-10 19:03:36 +01:00
Simon De Backer d0c129478e Mod Cmake en preprocessor 2020-12-10 00:08:26 +01:00
Simon De Backer 4de9c1d922 Add Test google mock
for imitating QET on tests (a file, a netwerk link, ...)
2020-12-09 10:48:38 +01:00
Simon De Backer d89d1088a3 Cmake for UI files auto link
this is one of the errors:
the ui files must be linked and changed to h files
so the h files found in the code by preprocessor
2020-12-09 10:40:12 +01:00
Simon De Backer 6556fbaf38 Add QT test to tests 2020-12-08 21:00:43 +01:00
Simon De Backer c83388c1d5 Add Test files 2020-12-08 20:44:50 +01:00
Simon De Backer 10c4c3d528 Wip Fix preprocessor on Cmake 2020-12-08 19:57:35 +01:00
Simon De Backer 6cd6efaca9 Add Catch2 and Google Test on Cmake
ToDo:
- Add compiling QElectroTech on Cmake (help needed)
- more Tests?
   - Qt Test
   - Boost Test

to test
run qtcreator
File >  open => CMakeLists.txt
2020-12-08 12:18:20 +01:00