Merge pull request #1247 from ispyisail/fix/stable-potential-text

Fix wire number moving between tied wires from run to run
This commit is contained in:
Laurent Trinques
2026-10-02 13:43:37 +02:00
committed by GitHub
4 changed files with 462 additions and 2 deletions
+48 -2
View File
@@ -2305,6 +2305,38 @@ QPointF Conductor::movePointIntoPolygon(const QPointF &point, const QPainterPath
}
}
namespace {
/// The two ends of @p conductor on the folio, smaller first, compared
/// by x then y.
QPair<QPointF, QPointF> conductorEnds(const Conductor *conductor)
{
auto less = [](const QPointF &a, const QPointF &b) {
return a.x() < b.x() || (a.x() == b.x() && a.y() < b.y());
};
QPointF a = conductor->terminal1 ? conductor->terminal1->dockConductor() : QPointF();
QPointF b = conductor->terminal2 ? conductor->terminal2->dockConductor() : QPointF();
if (less(b, a))
std::swap(a, b);
return qMakePair(a, b);
}
/// True if @p a comes before @p b in an order that is the same in every
/// run: by where the conductor's ends are on the folio, then by uuid.
/// Not by uuid first: a project generated again by a script gets new
/// uuids each time, and a file with no conductor uuids gets new ones on
/// every load, while the drawing is the same.
bool stableConductorLess(const Conductor *a, const Conductor *b)
{
const auto ea = conductorEnds(a), eb = conductorEnds(b);
const qreal ka[4] = {ea.first.x(), ea.first.y(), ea.second.x(), ea.second.y()};
const qreal kb[4] = {eb.first.x(), eb.first.y(), eb.second.x(), eb.second.y()};
for (int i = 0; i < 4; ++i)
if (ka[i] != kb[i])
return ka[i] < kb[i];
return a->uuid() < b->uuid();
}
}
/**
@brief longestConductorInPotential
@param conductor : a conductor in the potential to search
@@ -2313,10 +2345,24 @@ QPointF Conductor::movePointIntoPolygon(const QPointF &point, const QPainterPath
*/
Conductor * longestConductorInPotential(Conductor *conductor, bool all_diagram) {
Conductor *longest_conductor = conductor;
//Search the longest conductor
qreal longest_length = conductor->length();
//Search the longest conductor.
//Conductors of equal length are common (a symmetrical layout), and the
//set is iterated in pointer order, which changes from run to run: so a
//tie is broken by an order that does not, or the potential's text lands
//on a different conductor each time the same file is opened or exported.
foreach (Conductor *c, conductor -> relatedPotentialConductors(all_diagram))
if (c -> length() > longest_conductor -> length())
{
const qreal length = c->length();
if (qAbs(length - longest_length) < 1e-6) {
if (stableConductorLess(c, longest_conductor))
longest_conductor = c;
}
else if (length > longest_length) {
longest_conductor = c;
longest_length = length;
}
}
return longest_conductor;
}
+13
View File
@@ -395,6 +395,19 @@ target_compile_definitions(tst_wiringlistexport PRIVATE
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\""
"QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"")
# One text per potential: the number goes on the same conductor in every
# run when two conductors tie for longest. Exports
# fixtures/one_text_per_potential_tie.qet through the real binary, several
# times, since the order it used to depend on changes only between runs.
add_executable(
tst_potentialtextcarrier
tst_potentialtextcarrier.cpp)
add_test(NAME tst_potentialtextcarrier COMMAND tst_potentialtextcarrier)
add_dependencies(tst_potentialtextcarrier qelectrotech)
target_link_libraries(tst_potentialtextcarrier PRIVATE Qt::Test)
target_compile_definitions(tst_potentialtextcarrier PRIVATE
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
# Hops where wires cross (issue #436): the geometry in wirehops.cpp, and
# through the real binary, that --resave keeps the project setting and
# adds nothing to a project without it.
@@ -0,0 +1,320 @@
<project title="one text per potential, tied lengths" uuid="{74544bb0-3f71-58af-9052-eb46f8a03dfd}" version="0.200.1">
<properties>
<property name="saveddate" show="1">10/2/26</property>
<property name="saveddate-eu" show="1">02-10-2026</property>
<property name="saveddate-us" show="1">2026-10-02</property>
<property name="savedfilename" show="1">one_text_per_potential_tie</property>
<property name="savedfilepath" show="1">one_text_per_potential_tie.qet</property>
<property name="savedtime" show="1">22:07</property>
</properties>
<usage enabled="true" time_spent="0"/>
<newdiagrams>
<border cols="17" colsize="60" displaycols="true" displayrows="true" rows="8" rowsize="80"/>
<inset author="" auto_page_num="" date="null" displayAt="bottom" filename="" folio="" indexrev="" locmach="" plant="" title="" version=""/>
<conductors bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
<report label="%f-%l%c"/>
<xrefs>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="coil" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="commutator" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="plc" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="protection" xrefpos="AlignBottom"/>
</xrefs>
<conductors_autonums auto_break_conductors="false" current_autonum="" freeze_new_conductors="false"/>
<folio_autonums/>
<element_autonums current_autonum="" freeze_new_elements="false"/>
<guides/>
</newdiagrams>
<diagram author="" auto_page_num="" cols="17" colsize="60" date="null" displayAt="bottom" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="660" indexrev="" locmach="" order="1" plant="" rows="8" rowsize="80" title="" uuid="{91957ff3-7b74-4012-a876-f858c68b2d60}" version="0.200.1-dev">
<defaultconductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="1" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
<elements>
<element freezeLabel="false" is_movable="1" orientation="0" prefix="R" type="embed://import/10_electric/10_allpole/395_electronics_semiconductors/01_resistors/resistance.elmt" uuid="{3817b0a1-cab7-454e-81f2-7678b242cced}" x="100" y="300" z="10">
<terminals>
<terminal id="0" orientation="0" x="0" y="-16"/>
<terminal id="1" orientation="2" x="0" y="16"/>
</terminals>
<inputs/>
<dynamic_texts>
<dynamic_elmt_text Halignment="AlignLeft" Valignment="AlignTop" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular" frame="false" keep_visual_rotation="false" rotation="0" rotation_point_center="false" text_from="ElementInfo" text_width="-1" uuid="{1a7d317c-51b7-402f-807e-79aa136df233}" x="6" y="-11.5">
<text></text>
<info_name>label</info_name>
</dynamic_elmt_text>
</dynamic_texts>
<texts_groups/>
</element>
<element freezeLabel="false" is_movable="1" orientation="0" prefix="R" type="embed://import/10_electric/10_allpole/395_electronics_semiconductors/01_resistors/resistance.elmt" uuid="{f571bdba-9562-4119-8a18-0d798ebb7c3d}" x="300" y="100" z="10">
<terminals>
<terminal id="2" orientation="0" x="0" y="-16"/>
<terminal id="3" orientation="2" x="0" y="16"/>
</terminals>
<inputs/>
<dynamic_texts>
<dynamic_elmt_text Halignment="AlignLeft" Valignment="AlignTop" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular" frame="false" keep_visual_rotation="false" rotation="0" rotation_point_center="false" text_from="ElementInfo" text_width="-1" uuid="{79099d69-dcec-4247-bd03-cdb07a0194d6}" x="6" y="-11.5">
<text></text>
<info_name>label</info_name>
</dynamic_elmt_text>
</dynamic_texts>
<texts_groups/>
</element>
<element freezeLabel="false" is_movable="1" orientation="0" prefix="R" type="embed://import/10_electric/10_allpole/395_electronics_semiconductors/01_resistors/resistance.elmt" uuid="{c05fe3f1-f4a1-4beb-843b-90aadc3ca6c0}" x="300" y="500" z="10">
<terminals>
<terminal id="4" orientation="0" x="0" y="-16"/>
<terminal id="5" orientation="2" x="0" y="16"/>
</terminals>
<inputs/>
<dynamic_texts>
<dynamic_elmt_text Halignment="AlignLeft" Valignment="AlignTop" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular" frame="false" keep_visual_rotation="false" rotation="0" rotation_point_center="false" text_from="ElementInfo" text_width="-1" uuid="{075df885-82c2-49dd-817d-809137a3329d}" x="6" y="-11.5">
<text></text>
<info_name>label</info_name>
</dynamic_elmt_text>
</dynamic_texts>
<texts_groups/>
</element>
<element freezeLabel="false" is_movable="1" orientation="0" prefix="R" type="embed://import/10_electric/10_allpole/395_electronics_semiconductors/01_resistors/resistance.elmt" uuid="{d0acb0f6-8c2f-4daa-8365-7ad1df6f7f86}" x="400" y="300" z="10">
<terminals>
<terminal id="6" orientation="0" x="0" y="-16"/>
<terminal id="7" orientation="2" x="0" y="16"/>
</terminals>
<inputs/>
<dynamic_texts>
<dynamic_elmt_text Halignment="AlignLeft" Valignment="AlignTop" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular" frame="false" keep_visual_rotation="false" rotation="0" rotation_point_center="false" text_from="ElementInfo" text_width="-1" uuid="{11eafa99-e5a9-4baf-a2ed-8469780c7fa8}" x="6" y="-11.5">
<text></text>
<info_name>label</info_name>
</dynamic_elmt_text>
</dynamic_texts>
<texts_groups/>
</element>
</elements>
<conductors>
<conductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" element1="{3817b0a1-cab7-454e-81f2-7678b242cced}" element1_label="" element1_name="Resistor" element2="{f571bdba-9562-4119-8a18-0d798ebb7c3d}" element2_label="" element2_name="Resistor" formula="" freezeLabel="false" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="42" numsize="7" onetextperfolio="1" tension_protocol="" terminal1="{09a3060b-a0fd-41ad-b605-f5c0ae63901e}" terminal2="{4410c57c-3796-4696-b63b-d8d5a0c9b788}" terminalname1="A2" terminalname2="A1" text_color="#000000" type="multi" uuid="{26591715-c028-44c9-bf2d-c828f8187527}" vertical-alignment="AlignRight" vertirotatetext="270" x="0" y="0">
<sequentialNumbers/>
</conductor>
<conductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" element1="{f571bdba-9562-4119-8a18-0d798ebb7c3d}" element1_label="" element1_name="Resistor" element2="{c05fe3f1-f4a1-4beb-843b-90aadc3ca6c0}" element2_label="" element2_name="Resistor" formula="" freezeLabel="false" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="42" numsize="7" onetextperfolio="1" tension_protocol="" terminal1="{4410c57c-3796-4696-b63b-d8d5a0c9b788}" terminal2="{09a3060b-a0fd-41ad-b605-f5c0ae63901e}" terminalname1="A1" terminalname2="A2" text_color="#000000" type="multi" uuid="{0c9e2a9a-f402-49f4-9780-a8c72704acff}" vertical-alignment="AlignRight" vertirotatetext="270" x="0" y="0">
<sequentialNumbers/>
</conductor>
<conductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" element1="{f571bdba-9562-4119-8a18-0d798ebb7c3d}" element1_label="" element1_name="Resistor" element2="{d0acb0f6-8c2f-4daa-8365-7ad1df6f7f86}" element2_label="" element2_name="Resistor" formula="" freezeLabel="false" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="42" numsize="7" onetextperfolio="1" tension_protocol="" terminal1="{4410c57c-3796-4696-b63b-d8d5a0c9b788}" terminal2="{09a3060b-a0fd-41ad-b605-f5c0ae63901e}" terminalname1="A1" terminalname2="A2" text_color="#000000" type="multi" uuid="{5ecce027-3b6b-4e2e-9d30-f5dd59b320c0}" vertical-alignment="AlignRight" vertirotatetext="270" x="0" y="0">
<sequentialNumbers/>
</conductor>
</conductors>
</diagram>
<collection>
<category name="import">
<names>
<name lang="ca">Elements importats</name>
<name lang="cs">Zavedené prvky</name>
<name lang="da">Importerede elementer</name>
<name lang="de">Importierte Elemente</name>
<name lang="el">Εισηγμένα στοιχεία</name>
<name lang="en">Imported elements</name>
<name lang="es">Elementos importados</name>
<name lang="fr">Éléments importés</name>
<name lang="hr">Uvezeni elementi</name>
<name lang="it">Elementi importati</name>
<name lang="ja">インバートされた要素</name>
<name lang="ko">전기 심볼 요소</name>
<name lang="ko_KR">전기 심볼 요소</name>
<name lang="nl">Elementen geïmporteerd</name>
<name lang="nl_BE">Elementen geïmporteerd</name>
<name lang="pl">Elementy importowane</name>
<name lang="pt">Elementos importados</name>
<name lang="pt_BR">Elementos importados</name>
<name lang="ro">Elemente importate</name>
<name lang="ru">Импортированные элементы</name>
<name lang="sl">Uvoženi elementi</name>
<name lang="sv">Importerade element</name>
<name lang="tr">İthal öğeler</name>
<name lang="uk">Імпортовані елементи</name>
<name lang="zh">导入元件</name>
</names>
<category name="10_electric">
<names>
<name lang="ar">كهربائي</name>
<name lang="ca">Elèctric</name>
<name lang="cs">Elektrotechnika</name>
<name lang="da">Elektrisk</name>
<name lang="de">Elektrik</name>
<name lang="el">Ηλεκτρικά</name>
<name lang="en">Electric</name>
<name lang="es">Eléctrica</name>
<name lang="fi">Sähkö</name>
<name lang="fr">Electrique</name>
<name lang="hr">Električno</name>
<name lang="hu">Elektromos</name>
<name lang="it">Elettrica</name>
<name lang="ja">電気</name>
<name lang="ko">전기</name>
<name lang="mn">Цахилгаан</name>
<name lang="nb">Elektrisk</name>
<name lang="nl">Elektrotechniek</name>
<name lang="nl_BE">Elektrisch</name>
<name lang="pl">Elektrotechnika</name>
<name lang="pt">Elétrico</name>
<name lang="pt_BR">Elétrica</name>
<name lang="ro">Electric</name>
<name lang="ru">Электротехника</name>
<name lang="sk">Elektrické</name>
<name lang="sl">Elektrika</name>
<name lang="sr">Електрика</name>
<name lang="sv">El</name>
<name lang="tr">Elektrik</name>
<name lang="uk">Електрика</name>
<name lang="zh">10_电气</name>
<name lang="zn">电气工程</name>
</names>
<category name="10_allpole">
<names>
<name lang="ar">متعدد الأقطاب</name>
<name lang="ca">Multifilar</name>
<name lang="cs">Vícežilový</name>
<name lang="da">Flere ledere</name>
<name lang="de">Allpolig</name>
<name lang="el">Πολυγραμμικό</name>
<name lang="en">All-pole</name>
<name lang="es">Multifilar</name>
<name lang="fi">Yleisnapa</name>
<name lang="fr">Multifilaire</name>
<name lang="hr">Univerzalni</name>
<name lang="hu">Többvonalas szimbólumok</name>
<name lang="it">Multifilare</name>
<name lang="ja">複線</name>
<name lang="ko">다-극</name>
<name lang="mn">Бүх туйл</name>
<name lang="nb">Alle poler</name>
<name lang="nl">Veel polig</name>
<name lang="nl_BE">All-pole</name>
<name lang="pl">Schematy wieloliniowe</name>
<name lang="pt">Multipolar</name>
<name lang="pt_BR">Multifilar</name>
<name lang="ro">Bipolar</name>
<name lang="ru">Многополюсные</name>
<name lang="sk">Všepólové</name>
<name lang="sl">Vsi poli</name>
<name lang="sr">Свe-полни</name>
<name lang="sv">Allpolig</name>
<name lang="tr">Çok kutuplu</name>
<name lang="uk">Багатополюсні</name>
<name lang="zh">10_全极</name>
</names>
<category name="395_electronics_semiconductors">
<names>
<name lang="ar">إلكترونيات وأشباه موصلات</name>
<name lang="ca">Electrònica i semiconductors</name>
<name lang="cs">Elektronika a polovodiče</name>
<name lang="da">Elektronik og halvledere</name>
<name lang="de">Elektronik und Halbleiter</name>
<name lang="el">Ηλεκτρονικά και ημιαγωγοί</name>
<name lang="en">Electronics and semiconductors</name>
<name lang="es">Electrónica y semiconductores</name>
<name lang="fi">Elektroniikka ja puolijohteet</name>
<name lang="fr">Electronique et semi-conducteurs</name>
<name lang="hr">Elektronika i poluvodiči</name>
<name lang="hu">Elektronika és félvezetők</name>
<name lang="it">Elettronica e semiconduttori</name>
<name lang="ja">電子と半導体</name>
<name lang="ko">전자 공학 및 반도체</name>
<name lang="mn">Электроник ба хагас дамжуулагч</name>
<name lang="nb">Elektronikk og halvledere</name>
<name lang="nl">Electronica en halfgeleiders</name>
<name lang="nl_BE">Elektronica en halfgeleiders</name>
<name lang="pl">Elektronika i półprzewodniki</name>
<name lang="pt">Eletrónica e semicondutores</name>
<name lang="pt_BR">Eletrônica e semi-condutoues</name>
<name lang="ro">Electronică și semiconductoare</name>
<name lang="ru">Электроника и полупроводники</name>
<name lang="sk">Elektronika a polovodiče</name>
<name lang="sl">Elektronika in polprevodniki</name>
<name lang="sr">Електроника и полупроводници</name>
<name lang="sv">Elektronik och halvledare</name>
<name lang="tr">Elektronik ve yarı iletkenler</name>
<name lang="uk">Електроніка та напівпровідники</name>
<name lang="zh">电子与半导体</name>
</names>
<category name="01_resistors">
<names>
<name lang="ar">مُقاومة</name>
<name lang="ca">Resistències</name>
<name lang="cs">Odpory</name>
<name lang="da">Modstande</name>
<name lang="de">Widerstände</name>
<name lang="el">Αντιστάσεις</name>
<name lang="en">Resistors</name>
<name lang="es">Resistencias</name>
<name lang="fi">Vastukset</name>
<name lang="fr">Résistances</name>
<name lang="hr">Otpornici</name>
<name lang="hu">Ellenállások</name>
<name lang="it">Resistori</name>
<name lang="ja">抵抗器</name>
<name lang="ko">저항</name>
<name lang="mn">Эсэргүүцэл</name>
<name lang="nb">Motstander</name>
<name lang="nl">Weerstand</name>
<name lang="nl_BE">Weerstanden</name>
<name lang="pl">Rezystory</name>
<name lang="pt">Resistência</name>
<name lang="pt_BR">Resistores</name>
<name lang="ro">Rezistoare</name>
<name lang="ru">Резисторы</name>
<name lang="sk">Rezistory</name>
<name lang="sl">Upori</name>
<name lang="sr">Отпорници</name>
<name lang="sv">Motstånd</name>
<name lang="tr">Dirençler</name>
<name lang="uk">Резистори</name>
<name lang="zh">电阻器</name>
</names>
<element name="resistance.elmt">
<definition height="60" hotspot_x="10" hotspot_y="30" link_type="simple" type="element" version="0.100.0" width="20">
<uuid uuid="{2becfcef-f6f6-6a63-ef49-65f12026c4f8}"/>
<names>
<name lang="ar">مُقاومة</name>
<name lang="ca">Resistència</name>
<name lang="cs">Odpor</name>
<name lang="da">Modstand</name>
<name lang="de">Widerstand</name>
<name lang="el">Αντίσταση</name>
<name lang="en">Resistor</name>
<name lang="es">Resistencia</name>
<name lang="fi">Vastus</name>
<name lang="fr">Résistance</name>
<name lang="hr">Otpornik</name>
<name lang="hu">Ellenállás</name>
<name lang="it">Resistore</name>
<name lang="ja">抵抗器</name>
<name lang="ko">저항</name>
<name lang="mn">Резистор</name>
<name lang="nb">Motstand</name>
<name lang="nl">Weerstand</name>
<name lang="nl_BE">Weerstand</name>
<name lang="pl">Rezystor</name>
<name lang="pt">Resistência</name>
<name lang="pt_BR">Resistor</name>
<name lang="ro">Rezistor</name>
<name lang="ru">Резистор</name>
<name lang="sk">Rezistor</name>
<name lang="sl">Upor</name>
<name lang="sr">Отпорник</name>
<name lang="sv">Resistor</name>
<name lang="tr">Direnç</name>
<name lang="uk">Резистор</name>
<name lang="zh">电阻</name>
</names>
<informations>EN 60617: 04-01-01</informations>
<description>
<line antialias="false" end1="none" end2="none" length1="1.5" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black" x1="0" x2="0" y1="20" y2="-20"/>
<rect antialias="false" height="20" rx="0" ry="0" style="line-style:normal;line-weight:normal;filling:white;color:black" width="8" x="-4" y="-10"/>
<dynamic_text Halignment="AlignLeft" Valignment="AlignTop" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular" frame="false" keep_visual_rotation="false" rotation="0" text_from="ElementInfo" text_width="-1" uuid="{570cd854-578d-4c4b-bd2a-3498353e46b6}" x="6" y="-11.5" z="7">
<text/>
<info_name>label</info_name>
</dynamic_text>
<terminal name="A2" orientation="s" type="Generic" uuid="{09a3060b-a0fd-41ad-b605-f5c0ae63901e}" x="0" y="20"/>
<terminal name="A1" orientation="n" type="Generic" uuid="{4410c57c-3796-4696-b63b-d8d5a0c9b788}" x="0" y="-20"/>
</description>
</definition>
</element>
</category>
</category>
</category>
</category>
</category>
</collection>
</project>
+81
View File
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QtTest>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QProcessEnvironment>
#include <QRegularExpression>
#include <QTemporaryDir>
// With "one text per potential" on, the potential's number is drawn on its
// longest conductor. fixtures/one_text_per_potential_tie.qet has two
// conductors of the same, greatest length in one potential: which of them
// carried the number used to follow pointer order, so the same file
// exported twice could put it on either. Runs the real binary, in separate
// processes, since that order only changes from one run to the next.
class tst_potentialtextcarrier : public QObject
{
Q_OBJECT
QTemporaryDir m_dir;
// Export the fixture to SVG and return where the number is drawn: the
// transform of the group holding it. Empty if it is not drawn exactly
// once.
QString carrier(int run)
{
const QString home = m_dir.filePath(QStringLiteral("home%1").arg(run));
const QString out = m_dir.filePath(QStringLiteral("svg%1").arg(run));
QDir().mkpath(home);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
env.insert(QStringLiteral("HOME"), home);
env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config"));
env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/data"));
env.insert(QStringLiteral("TMPDIR"), home);
QProcess proc;
proc.setProcessEnvironment(env);
proc.start(QStringLiteral(QET_TEST_BINARY_PATH),
{QStringLiteral("--export-svg"),
QFINDTESTDATA("fixtures/one_text_per_potential_tie.qet"), out});
if (!proc.waitForFinished(60000) || proc.exitCode() != 0)
return {};
const QStringList svgs = QDir(out).entryList({QStringLiteral("*.svg")});
if (svgs.size() != 1)
return {};
QFile f(QDir(out).filePath(svgs.first()));
if (!f.open(QIODevice::ReadOnly))
return {};
const QString svg = QString::fromUtf8(f.readAll());
static const QRegularExpression re(
QStringLiteral("transform=\"([^\"]*)\"[^<]*>\\s*<text[^>]*>42</text>"));
QStringList found;
auto it = re.globalMatch(svg);
while (it.hasNext())
found << it.next().captured(1);
return found.size() == 1 ? found.first() : QString();
}
private slots:
void initTestCase()
{
QVERIFY(m_dir.isValid());
QVERIFY(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)));
}
// Before the fix about half the runs differed from the first, so
// eight agreeing runs leave a 1 in 128 chance of a false pass.
void sameCarrierEveryRun()
{
const QString first = carrier(0);
QVERIFY2(!first.isEmpty(), "the number is not drawn exactly once");
for (int run = 1; run < 8; ++run)
QCOMPARE(carrier(run), first);
}
};
QTEST_GUILESS_MAIN(tst_potentialtextcarrier)
#include "tst_potentialtextcarrier.moc"