Put a potential's one text on the same conductor in every run

With "one text per potential" on, the number is drawn on the
potential's longest conductor. When two conductors tie for longest,
longestConductorInPotential() kept whichever it met first, iterating a
QSet<Conductor *> in pointer order -- which changes from run to run. The
same file, exported twice, could put the number on either conductor:
same numbers, different PDF.

A tie is now broken by where the conductors' ends are on the folio, then
by uuid. Not by uuid first: a file with no conductor uuids gets fresh
ones on every load, and a project generated again by a script gets new
ones each time, while the drawing is the same.

tst_potentialtextcarrier exports a fixture with such a tie eight times;
before the fix it failed in each of three tries.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-02 22:19:39 +13:00
parent 808d6a3c5b
commit eb2367e400
4 changed files with 462 additions and 2 deletions
+48 -2
View File
@@ -2311,12 +2311,58 @@ QPointF Conductor::movePointIntoPolygon(const QPointF &point, const QPainterPath
@param all_diagram : true -> search in the whole project, false -> search only in the diagram of conductor
@return the longest conductor in the same potential of conductor
*/
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();
}
}
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
@@ -388,6 +388,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"