diff --git a/tests/qttest/fixtures/every_feature.qet b/tests/qttest/fixtures/every_feature.qet
new file mode 100644
index 000000000..c5d372169
--- /dev/null
+++ b/tests/qttest/fixtures/every_feature.qet
@@ -0,0 +1,1893 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %date
+
+
+
+
+
+ %date1
+
+
+
+
+
+ %date
+
+
+
+
+
+
+ %title
+
+
+
+
+
+ %filename
+
+
+
+
+
+ %filename
+ %label4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DESSINE
+
+
+
+
+
+ %dessin
+
+
+
+
+
+ %label5
+
+
+
+
+
+ %rev
+
+
+
+
+
+ Emissionne
+ EMIS
+
+
+
+
+
+ %date2
+
+
+
+
+
+
+
+
+
+ CONTROL
+
+
+
+
+
+ %control
+
+
+
+
+
+ %label3
+
+
+
+
+
+
+
+
+
+ %{folio-id}
+
+
+
+
+
+ REV
+
+
+
+
+
+ MODIFICATION
+
+
+
+
+
+ %date
+
+
+
+
+
+ FIRME
+
+
+
+
+
+ APROUV
+
+
+
+
+
+ %aprouv
+
+
+
+
+
+ %label1
+
+
+
+
+
+ %label2
+
+
+
+
+
+ ORIGINE
+
+
+
+
+
+ %{folio-total}
+
+
+
+
+
+
+
+ 10/2/26
+ 02-10-2026
+ 2026-10-02
+ free_text_width
+ 18:39
+
+
+
+
+
+
+ ACME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ACME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+ 1
+
+ 01
+
+ 001
+ a
+
+
+
+
+
+
+
+
+
+
+ Aux 1
+ A comment
+ Description
+ Designation
+ K%prefix%M%LM%l%c%F%sequ_1%sequf_1%seqtf_1%seqhf_1%seqa_1
+ {8e52a483-68df-4a9e-9a81-c008e47aa9a6}
+ Motor start
+ KKPlant 0Cabinet 0C1F11101001a
+ Cabinet 0
+ MM-1
+ Maker
+ REF-1
+ Plant 0
+ 2
+ Supplier
+ 24V DC
+ pcs
+
+
+
+ A2
+ #aa5500
+
+
+ Free text
+
+
+ A comment
+ comment
+
+
+ KKPlant 0Cabinet 0C1F11101001a / A comment
+ %{label} / %{comment}
+
+
+ A1
+
+
+ KKPlant 0Cabinet 0C1F11101001a
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ label
+
+
+
+
+
+
+ 2
+
+ 2
+
+ 02
+
+ 002
+ b
+
+
+
+
+
+
+
+
+ K%prefix%M%LM%l%c%F%sequ_1%sequf_1%seqtf_1%seqhf_1%seqa_1
+ {8e52a483-68df-4a9e-9a81-c008e47aa9a6}
+ KXPlant 0Cabinet 0E4F12202002b
+
+
+
+
+
+
+ KXPlant 0Cabinet 0E4F12202002b
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Aux auxiliary1
+ Aux auxiliary2
+ Aux auxiliary3
+ Aux auxiliary4
+ Category
+ 2A
+ 20
+ Aux description_auxiliary1
+ Aux description_auxiliary2
+ Aux description_auxiliary3
+ Aux description_auxiliary4
+ Aux designation_auxiliary1
+ Aux designation_auxiliary2
+ Aux designation_auxiliary3
+ Aux designation_auxiliary4
+ 10
+ Aux machine_manufacturer_reference_auxiliary1
+ Aux machine_manufacturer_reference_auxiliary2
+ Aux machine_manufacturer_reference_auxiliary3
+ Aux machine_manufacturer_reference_auxiliary4
+ Aux manufacturer_auxiliary1
+ Aux manufacturer_auxiliary2
+ Aux manufacturer_auxiliary3
+ Aux manufacturer_auxiliary4
+ Aux manufacturer_reference_auxiliary1
+ Aux manufacturer_reference_auxiliary2
+ Aux manufacturer_reference_auxiliary3
+ Aux manufacturer_reference_auxiliary4
+ Model
+ Notes
+ 1
+ 1
+ 1
+ 1
+ Aux supplier_auxiliary1
+ Aux supplier_auxiliary2
+ Aux supplier_auxiliary3
+ Aux supplier_auxiliary4
+ Aux unity_auxiliary1
+ Aux unity_auxiliary2
+ Aux unity_auxiliary3
+ Aux unity_auxiliary4
+ 24V
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ label
+
+
+ ÖLFLEX 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2-D0
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+ 01
+ 01
+ 001
+ 001
+ a
+
+
+
+
+ 2
+ 2
+ 2
+ 02
+ 02
+ 002
+ 002
+ b
+
+
+
+
+ 3
+ 3
+ 3
+ 03
+ 03
+ 003
+ 003
+ c
+
+
+
+
+ 5
+ 5
+ 5
+ 05
+ 05
+ 005
+ 005
+ e
+
+
+
+
+ 4
+ 4
+ 4
+ 04
+ 04
+ 004
+ 004
+ d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1-D11
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KKPlant 0Cabinet 0C1F11101001a
+ label
+
+
+
+
+
+
+ 3
+
+ 3
+
+ 03
+
+ 003
+ c
+
+
+
+
+
+
+
+ Aux 1
+ Description
+ Designation
+ K%prefix%M%LM%l%c%F%sequ_1%sequf_1%seqtf_1%seqhf_1%seqa_1
+ {8e52a483-68df-4a9e-9a81-c008e47aa9a6}
+ Motor start
+ KKPlant 1Cabinet 1B6F23303003c
+ MM-1
+ Maker
+ REF-1
+ Plant 0
+ 2
+ Supplier
+ pcs
+
+
+
+ A2
+
+
+ A1
+
+
+ KKPlant 1Cabinet 1B6F23303003c
+ label
+
+
+ Free text
+
+
+
+ comment
+
+
+ KKPlant 1Cabinet 1B6F23303003c /
+ %{label} / %{comment}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ A2
+
+
+ A1
+
+
+
+ label
+
+
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAICAIAAAB/FOjAAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAGklEQVQYlWNkYGgQYGAgHrEwKDCQBEY1EAMA3O4CbvRC5WAAAAAASUVORK5CYII=
+
+
+
+
+
+
+
+ 5;5;10;5
+
+
+
+ nomenclature
+ SELECT label, designation, manufacturer, manufacturer_reference, quantity FROM element_nomenclature_view WHERE ( element_type = 'terminal' OR element_type = 'thumbnail' OR element_type = 'simple' OR element_type = 'master' OR element_type = 'slave') ORDER BY label, designation, manufacturer, manufacturer_reference, quantity
+
+
+ Liberation Sans,9,-1,0,50,0,0,0,0,0,Regular
+ AlignLeft
+
+
+
+
+
+
+
+ 5;5;10;5
+
+
+
+ summary
+ SELECT pos, title, author, folio FROM project_summary_view
+
+
+ Liberation Sans,9,-1,0,50,0,0,0,0,0,Regular
+ AlignLeft
+
+
+
+
+
+
+
+
+
+
+
+
+ 5;5;10;5
+
+
+
+
+
+
+
+
+
+
+ Plant 0
+ Cabinet 0
+ X1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Imported elements
+
+
+
+ Test
+
+
+
+
+
+ ملف
+ Bobina
+ Cívka relé
+ Relæ
+ Spule
+ Πηνίο
+ Coil
+ Bobina
+ Käämi
+ Bobine
+ Zavojnica
+ Tekercs
+ Bobina
+ コイル
+ 코일
+ Ороомог
+ Spole
+ Spoel
+ Relais spoel (algemeen)
+ Cewka
+ Bobina
+ Bobina
+ Bobina
+ Обмотка
+ Cievka
+ Tuljava
+ Каlem
+ Spole
+ Bobin
+ Котушка
+ 三线圈
+
+
+ plc
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+ A2
+
+
+ A1
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+ كهربائي
+ Elèctric
+ Elektrotechnika
+ Elektrisk
+ Elektrik
+ Ηλεκτρικά
+ Electric
+ Eléctrica
+ Sähkö
+ Electrique
+ Električno
+ Elektromos
+ Elettrica
+ 電気
+ 전기
+ Цахилгаан
+ Elektrisk
+ Elektrotechniek
+ Elektrisch
+ Elektrotechnika
+ Elétrico
+ Elétrica
+ Electric
+ Электротехника
+ Elektrické
+ Elektrika
+ Електрика
+ El
+ Elektrik
+ Електрика
+ 10_电气
+ 电气工程
+
+
+
+ متعدد الأقطاب
+ Multifilar
+ Vícežilový
+ Flere ledere
+ Allpolig
+ Πολυγραμμικό
+ All-pole
+ Multifilar
+ Yleisnapa
+ Multifilaire
+ Univerzalni
+ Többvonalas szimbólumok
+ Multifilare
+ 複線
+ 다-극
+ Бүх туйл
+ Alle poler
+ Veel polig
+ All-pole
+ Schematy wieloliniowe
+ Multipolar
+ Multifilar
+ Bipolar
+ Многополюсные
+ Všepólové
+ Vsi poli
+ Свe-полни
+ Allpolig
+ Çok kutuplu
+ Багатополюсні
+ 10_全极
+
+
+
+ المرحّلات والموصّلات وجهات الاتصال
+ Relés, contactors i contactes
+ Relé, stykače a kontakty
+ Relæer, kontaktorer og kontakter
+ Relais, Schütze und Kontakte
+ Ηλεκτρονόμοι και επαφές
+ Relays, contactors and contacts
+ Relevadores, contactores y contactos
+ Releet, kontaktorit ja koskettimet
+ Relais, contacteurs et contacts
+ Releji, kontaktori i kontakti
+ Relék, kontaktorok és érintkezők
+ Relè, contattori e contatti
+ 継電器、接触器、接点
+ 릴레이, 커넥터및 접점
+ Реле, контактор болон контакт
+ Reléer, kontaktorere og kontakter
+ Relais, contactoren en contacten
+ Relais, contacteurs en contacten
+ Przekaźniki i styczniki
+ Relés, contatores e contactos
+ Relés, Contatores e contatos
+ Relee, contactoare și contacte
+ Реле, пускатели и контакты
+ Relé, stykače a kontakty
+ Releji, kontaktorji in kontakti
+ Релеји, контактори и контакти
+ Reläer, kontaktorer och kontakter
+ Röleler, kontaktörler ve kontaklar
+ Реле, контактори та контакти
+ 继电器、接触器与触点
+
+
+
+ لفه
+ Bobines
+ cívka
+ spole
+ Spule
+ σπείρα
+ coil
+ bobina
+ Käämi
+ bobine
+ zavojnica
+ tekercs
+ bobina
+ コイル
+ 코일
+ ороомог
+ Spole
+ spoel
+ Spoel
+ cewka
+ bobina
+ bobina
+ bobina
+ катушка
+ Cievka
+ tuljava
+ калем
+ spole
+ bobin
+ котушка
+ 线圈
+
+
+
+
+
+ ملف
+ Bobina
+ Cívka relé
+ Relæ
+ Spule
+ Πηνίο
+ Coil
+ Bobina
+ Käämi
+ Bobine
+ Zavojnica
+ Tekercs
+ Bobina
+ コイル
+ 코일
+ Ороомог
+ Spole
+ Spoel
+ Relais spoel (algemeen)
+ Cewka
+ Bobina
+ Bobina
+ Bobina
+ Обмотка
+ Cievka
+ Tuljava
+ Каlem
+ Spole
+ Bobin
+ Котушка
+ 三线圈
+
+
+ coil
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+ A2
+
+
+ A1
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+ تماسات مع إحالات
+ Contactes amb referències creuades
+ Kontakty s křížovými odkazy
+ Kontaker med krydsreference
+ Kontakte mit Querverweis
+ Επαφές με παραπομπές
+ Contacts with cross referencing
+ Contactos con referencia cruzada
+ Kosketimet lehtiviittauksella
+ Contacts avec référence croisée
+ Kontakti s unakrsnim referenciranjem
+ Érintkezők kereszthivatkozásokkal
+ Contatti con riferimenti incrociati
+ 相互参照付き接点
+ 교차 참조 접점
+ Харилцан холбоос бүхий контакт
+ Kontakter med kryssreferanse
+ Contacten met kruisreferentie
+ Contacten met kruisverwijzing
+ Zestyki (automatyczne oznaczenia)
+ Contactos com renvoi de folio
+ Contatos com referencia cruzada
+ Contacte cu renvoi de folio
+ Контакты с перекрестными ссылками
+ Kontakty s krížovým odkazom
+ Kontakti s sklici
+ Контакти са унакрсним референцирањем
+ Kontakter med bladhänvisning
+ Çapraz referanslı kontaklar
+ Контакти з перехресними посиланнями
+ 触点交叉引用
+
+
+
+ مساعد
+ Auxiliars
+ Pomocné kontakty
+ Hjælpe kontakter
+ Hilfsglieder
+ Βοηθητικές επαφές
+ Auxiliary
+ Contactos auxiliares
+ Apupiiri
+ Auxilliaires
+ Pomoćni
+ Segéd
+ Contatti ausiliari
+ 補助
+ 보조 접점
+ Туслах
+ Hjelpe
+ Hulpcontacten
+ Hulpcontacten
+ Zestyki pomocnicze
+ Auxiliar
+ Auxiliares
+ Auxiliare
+ Внешние
+ Pomocné
+ Pomožni
+ Помоћни
+ Hjälp
+ Yardımcı
+ Допоміжні
+ 辅助触点
+
+
+
+
+
+ مُلامس بسيط (NO)
+ Contacte senzill
+ Spínací kontakt
+ Enkel kontakt
+ Schliesser
+ Απλή επαφή, ανοικτή
+ Simple contact
+ Contactor simple
+ Yksinkertainen kosketin
+ Contact simple
+ Jednostavni kontakt
+ Egyszerű érintkező
+ Contatto semplice (NO)
+ 単純接点
+ 단순 접점
+ Энгийн контакт
+ Enkel kontakt
+ contact enkel
+ Eenvoudig contact
+ Zestyk zwierny
+ Contacto simples (NO)
+ Contato simples
+ Contact simplu
+ Проктой контакт (НР)
+ Jednoduchý kontakt
+ Enostavni kontakt
+ Прости контакт
+ Enkelkontakt
+ Basit kontak
+ Простий контакт
+ 简单连接器
+
+
+ simple
+ NO
+ 1
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+
+ مُلامس بسيط (NC)
+ Contacte simple (NC)
+ Rozpínací kontakt
+ Enkel kontakt (NC)
+ Öffner
+ Απλή επαφή, κλειστή
+ Simple contact (NC)
+ Contactor simple (NC)
+ Yksinkertainen kosketin (NC)
+ Contact simple (NF)
+ Jednostavni kontakt (NC)
+ Egyszerű érintkező (NC)
+ Contatto semplice (NC)
+ 単純接点 (NC)
+ 단순 접점 (NC)
+ Энгийн контакт (NC)
+ Enkel kontakt (NC)
+ contact normaal gesloten enkel simpel (NC)
+ Eenvoudig contact (NC)
+ Zestyk rozwierny
+ Contacto simples (NC)
+ Contato simples (NF)
+ Contact simplu (NC)
+ Проктой контакт (НЗ)
+ Jednoduchý kontakt (NC)
+ Enostavni kontakt (NC)
+ Прости контакт (NC)
+ Enkelkontakt (NC)
+ Basit kontak (NC)
+ Простий контакт (NC)
+ 简单常闭连接器
+
+
+ simple
+ NC
+ 1
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+ قدرة
+ Potència
+ Silové kontakty
+ Hoved kontaktor
+ Leistung
+ Ισχύος
+ Power
+ Potencia
+ Teho
+ Puissance
+ Snaga
+ Teljesítmény
+ Potenza
+ 電力
+ 전력 접점
+ Цахилгаан
+ Kraft
+ Last contacten
+ Vermogen
+ Styczniki
+ Potência
+ Potencia
+ Putere
+ Силовые
+ Výkonové
+ Moč
+ Снага
+ Effekt
+ Güç
+ Живлення
+ 功率触点
+
+
+
+
+
+ مُلامس قدرة - كونتكتور (NO)
+ Contactar el contactor de potència
+ Silový kontakt 4p
+ Hovedkontakt kontaktor
+ Leistungsschliesser 4-polig
+ Επαφές ρελέ ισχύος, ανοικτές
+ Contact power contactor
+ Interruptor de potencia contactor
+ Koskettimen teho kontaktorille
+ Contact puissance contacteur
+ Kontakt snažnog kontaktora
+ Teljesítmény kontaktor érintkező
+ 4 Contatti NA di potenza
+ 電力用接触器接点
+ 전력 접점 접촉기
+ Контакт хүчний контактор
+ Kontakt kraftkontaktor
+ Last contact (NO)
+ Vermogenscontact contacteur
+ Stycznik
+ Interruptor de potência contactor
+ Contator de potência
+ Contact de putere contactor
+ Контакт контактора (НР)
+ Výkonový kontakt stýkača
+ Kontakt močnostnega kontaktorja
+ Контакт снаге контактора
+ Kontakt effektkontaktor
+ Güç kontağı kontaktör
+ Силовий контакт контактора
+ 常开功率触点6
+
+
+ power
+ NO
+ 4
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ طرفيات توصيل
+ Borns i regletes de borns
+ Svorky
+ Klemmer og klemmerækker
+ Klemmen und Klemmleisten
+ Ακροδέκτες και σειρές ακροδεκτών
+ Terminals and terminal strips
+ Terminales
+ Rimaelittimet
+ Bornes et borniers
+ Stezaljke i redne stezaljke
+ Sorkapcsok
+ Terminali
+ 端子と端子台
+ 단자 및 단자대
+ Клемм ба клеммын хавтан
+ Rekkeklemmer og klemlister
+ Klemmenlijst
+ Klemmen en klemmenstroken
+ Złącza i zaciski
+ Terminais
+ Bornes e borneiras
+ Borne și borniere
+ Клеммы и клеммники
+ Svorky a svorkovnice
+ Vrstne sponke in sponke
+ Клеме и редне клеме
+ Plintar och plintrader
+ Klemensler ve klemens şeritleri
+ Клеми та клемні колодки
+ 接线端子与端子排
+
+
+
+
+
+ طرف توصيل
+ Born de continuïtat
+ Spojovací svorka
+ Klemme
+ Klemme
+ Ακροδέκτης
+ Terminal block
+ Terminal de unión
+ Liitinrima
+ Borne continuité
+ Stezaljka
+ Sorkapocs
+ Terminale di unione
+ 端子ブロック
+ 단자 블록
+ Клеммын блок
+ Rekkeklemme
+ klem doorgang
+ Klemmenblok
+ Zacisk
+ Terminal de combinação
+ Borne de combinacao
+ Bloc de borne
+ Клеммное соединение
+ Svorkovnica
+ Vrstna sponka
+ Клемни блок
+ Plint
+ Klemens bloğu
+ Клемна колодка
+ 2号接线端子
+
+
+ generic
+ generic
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+ كابلات وتوصيلات
+ Cables i cablejat
+ Kabely a vodiče
+ Kabler og ledninger
+ Kabel und Verdrahtung
+ Καλώδια και καλωδίωση
+ Cables and wiring
+ Cables y alambres
+ Kaapelit ja johdotus
+ Câbles et filerie
+ Kabeli i ožičenje
+ Kábelek és vezetékek
+ Cavi e collegamenti
+ ケーブルと配線
+ 케이블 및 배선
+ Кабель ба утас
+ Kabler og ledninger
+ Kabels en draden
+ Kabels en bedrading
+ Przewody i kable
+ Cabos e cablagem
+ Cabos e fiação
+ Cabluri și cablare
+ Кабели и провода
+ Káble a vedenie
+ Kabli in ožičenje
+ Каблови и ожичење
+ Kablar och ledningsdragning
+ Kablolar ve kablolama
+ Кабелі та проводка
+ 电缆与布线
+
+
+
+
+
+ كابل 3 أسلاك
+ Cable 3 fils
+ Kabel 3x
+ Kabel 3 ledere
+ Kabel 3x
+ Καλώδιο 3 αγωγών
+ Cable 3 wires
+ Cable 3 alambres
+ Kaapeli 3 johdinta
+ Cable 3 brins
+ Kabel 3 žica
+ Kábel 3 + PE
+ Cavo a 3 conduttori
+ ケーブル 3 本
+ 케이블 3심
+ Кабель 3 утас
+ Kabel 3 ledere
+ Kabel 3 draden
+ Kabel 3 draden
+ Oznaczenie przewodu trójżyłowego
+ Cabo 3 fios
+ Cabo 3 condutores
+ Cablu 3 fire
+ Кабель 3 жилы
+ Kábel 3 vodičov
+ Kabel 3 žic
+ Кабл 3 жица
+ Kabel 3 trådar
+ Kablo 3 tel
+ Кабель 3 жил
+ 3线电缆
+
+ edited with "QET_ElementScaler"
+
+
+
+
+ label
+
+
+ ÖLFLEX 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+ إحالات
+ Referències als fulls
+ Odkazování listů
+ Ark henvisninger
+ Folienverweise
+ Αναφορές σελίδας
+ Folio referencing
+ Referencias
+ Lehtiviittaus
+ Reports de folio
+ Referenciranje folija
+ Tervlap hivatkozások
+ Riferimenti
+ フォリオ参照
+ 도면 간 참조
+ Хуудасны холбоос
+ Folio-referanse
+ Referenties
+ Folioverwijzing
+ Odsyłacze
+ Renvoi de folio
+ Referências
+ Renvoi de folio
+ Точки разрыва
+ Odkazy na listy
+ Sklici na list
+ Референцирање фолија
+ Bladhänvisning
+ Sayfa referansı
+ Посилання на аркуші
+ 图页引用
+
+
+
+
+
+ الصفحة التالية
+ Enllaç sortint
+ Další list
+ Går pil
+ Nächste Folie
+ Επόμενη σελίδα
+ Going arrow
+ Folio siguiente
+ Lähtevä nuoli
+ Folio suivant
+ Odlazna strelica
+ Elmenő hivatkozás
+ Foglio successivo
+ 出矢印
+ 나가는 화살표
+ Явж буй сум
+ Går pil
+ Referentie volgend
+ Gaande pijl
+ Wyjście adresowe
+ Seta de saída
+ Seta de saída (vai)
+ Săgeată de ieșire
+ Следующая страница
+ Odchádzajúca šípka
+ Odhodna puščica
+ Одлазна стрелица
+ Utgående pil
+ Giden ok
+ Стрілка виходу
+ 02引出箭头
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+ الصفحة السابقة
+ Enllaç entrant
+ Předchozí list
+ Kommer pil
+ Vorherige Folie
+ Προηγούμενη σελίδα
+ Coming arrow
+ folio anterior
+ Saapuva nuoli
+ Folio précédent
+ Dolazna strelica
+ Beérkező hivatkozás
+ Foglio precedente
+ 入り矢印
+ 들어오는 화살표
+ Ирж буй сум
+ Kommer pil
+ Referentie Vorig
+ Komende pijl
+ Wejście adresowe
+ Seta de entrada
+ Seta de entrada (vem)
+ Săgeată de intrare
+ Предыдущая страница
+ Prichádzajúca šípka
+ Prihajajoča puščica
+ Долазна стрелица
+ Inkommande pil
+ Gelen ok
+ Стрілка входу
+ 01引入箭头
+
+ Author: The QElectroTech team
+License: see http://qelectrotech.org/wiki/doc/elements_license
+
+
+
+
+
+ label
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qttest/tst_resaveunchanged.cpp b/tests/qttest/tst_resaveunchanged.cpp
index fe6a90a00..921b1bc8d 100644
--- a/tests/qttest/tst_resaveunchanged.cpp
+++ b/tests/qttest/tst_resaveunchanged.cpp
@@ -2,6 +2,7 @@
#include
#include
+#include
#include
#include
#include
@@ -35,7 +36,8 @@ class tst_resaveunchanged : public QObject
// --resave @p in to a new file, in a sandbox of its own (so a running
// QElectroTech cannot answer instead); returns the new file's path.
- QString resave(const QString &in, const QString &suffix = QStringLiteral(".qet"))
+ QString resave(const QString &in, const QString &suffix = QStringLiteral(".qet"),
+ bool eager = false)
{
//Always p.qet, in its own folder: an untitled project takes its
//file name as title, so two names would make two projects.
@@ -48,6 +50,11 @@ class tst_resaveunchanged : public QObject
env.insert(QStringLiteral("HOME"), home);
env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config"));
env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/data"));
+ if (eager) {
+ env.insert(QStringLiteral("QET_EAGER_FOLIOS"), QStringLiteral("1")); //every folio built on opening
+ } else {
+ env.remove(QStringLiteral("QET_EAGER_FOLIOS"));
+ }
QProcess proc;
proc.setProcessEnvironment(env);
proc.start(QStringLiteral(QET_TEST_BINARY_PATH), {QStringLiteral("--resave"), in, out});
@@ -385,6 +392,117 @@ private slots:
QCOMPARE(without_save_stamps(read(back)), without_save_stamps(read(straight)));
}
+ // The round trip between the formats (#1512): every example, and
+ // fixtures/every_feature.qet, a project using every feature
+ // QElectroTech saves (built through its script API, the few things the
+ // API cannot set added in the form QElectroTech saves them, then opened
+ // and saved by QElectroTech). For each, the save stamps aside:
+ // - a .qetz saved again is the same file;
+ // - a .qetz saved as a .qet is the project saved straight as a .qet;
+ // - that .qet saved as a .qetz is the project saved straight as a
+ // .qetz, part by part, its database row by row;
+ // - lazy folios save what every folio built saves, in both formats.
+ void roundTripBetweenFormats_data()
+ {
+ QTest::addColumn("project");
+ const QDir examples(QStringLiteral(QET_EXAMPLES_DIR));
+ for (const QString &name : examples.entryList({QStringLiteral("*.qet")}, QDir::Files, QDir::Name))
+ QTest::newRow(name.toUtf8().constData()) << examples.filePath(name);
+ QTest::newRow("every_feature.qet") << QFINDTESTDATA("fixtures/every_feature.qet");
+ }
+ void roundTripBetweenFormats()
+ {
+ QFETCH(QString, project);
+ const QString qet = resave(project);
+ QVERIFY2(!qet.isEmpty(), "--resave as .qet failed");
+ const QString qetz = resave(project, QStringLiteral(".qetz"));
+ QVERIFY2(!qetz.isEmpty(), "--resave as .qetz failed");
+
+ const QString qetz_again = resave(qetz, QStringLiteral(".qetz"));
+ QVERIFY2(!qetz_again.isEmpty(), "--resave of the .qetz failed");
+ QVERIFY2(read(qetz_again) == read(qetz), "a .qetz saved again changed");
+
+ const QString back = resave(qetz);
+ QVERIFY2(!back.isEmpty(), "--resave of the .qetz as .qet failed");
+ QCOMPARE(withoutSaveStamps(read(back)), withoutSaveStamps(read(qet)));
+
+ const QString zipped = resave(qet, QStringLiteral(".qetz"));
+ QVERIFY2(!zipped.isEmpty(), "--resave of the .qet as .qetz failed");
+ QCOMPARE(containerContent(zipped), containerContent(qetz));
+
+ const QString eager = resave(project, QStringLiteral(".qet"), true);
+ QVERIFY2(!eager.isEmpty(), "--resave with every folio built failed");
+ QCOMPARE(withoutSaveStamps(read(eager)), withoutSaveStamps(read(qet)));
+ const QString eager_zipped = resave(project, QStringLiteral(".qetz"), true);
+ QVERIFY2(!eager_zipped.isEmpty(), "--resave as .qetz with every folio built failed");
+ QCOMPARE(containerContent(eager_zipped), containerContent(qetz));
+ }
+
+ static QString withoutSaveStamps(const QByteArray &xml)
+ {
+ static const QRegularExpression stamp(QStringLiteral(
+ "\\s*]*name=\"saved(filename|filepath|filenamedir|date|date-us|date-eu|time)\"[^>]*>[^<]*"));
+ return QString::fromUtf8(xml).remove(stamp);
+ }
+
+ // What the .qetz @p path holds, its save stamps aside: one line per
+ // part, an XML part as its text, project.sqlite as its rows
+ static QStringList containerContent(const QString &path)
+ {
+ QList entries;
+ if (!QetZip::fromBytes(read(path), &entries)) return {QStringLiteral("not a zip")};
+ QStringList content;
+ for (const QetZip::Entry &entry : std::as_const(entries)) {
+ if (entry.name == QLatin1String("project.sqlite")) {
+ for (const QString &row : databaseRows(entry.data))
+ content << entry.name + QLatin1Char(' ') + row;
+ } else if (entry.name.endsWith(QLatin1String(".xml"))) {
+ content << entry.name + QLatin1Char(' ') + withoutSaveStamps(entry.data);
+ } else {
+ content << entry.name + QLatin1Char(' ')
+ + QString::fromLatin1(QCryptographicHash::hash(entry.data, QCryptographicHash::Sha1).toHex());
+ }
+ }
+ return content;
+ }
+
+ // Every row of every table of the SQLite database @p database, but the
+ // save stamps, as text
+ static QStringList databaseRows(const QByteArray &database)
+ {
+ sqlite3 *db = nullptr;
+ sqlite3_open(":memory:", &db);
+ unsigned char *copy = static_cast(sqlite3_malloc64(sqlite3_uint64(database.size())));
+ memcpy(copy, database.constData(), size_t(database.size()));
+ sqlite3_deserialize(db, "main", copy, database.size(), database.size(), SQLITE_DESERIALIZE_FREEONCLOSE);
+ QStringList tables;
+ sqlite3_stmt *list = nullptr;
+ sqlite3_prepare_v2(db, "SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name", -1, &list, nullptr);
+ while (list && sqlite3_step(list) == SQLITE_ROW)
+ tables << QString::fromUtf8(reinterpret_cast(sqlite3_column_text(list, 0)));
+ sqlite3_finalize(list);
+ static const QRegularExpression stamp(QStringLiteral(
+ "\\bsaved(filename|filepath|filenamedir|date|date-us|date-eu|time)\\b"));
+ QStringList rows;
+ for (const QString &table : std::as_const(tables)) {
+ sqlite3_stmt *select = nullptr;
+ sqlite3_prepare_v2(db, QStringLiteral("SELECT * FROM \"%1\"").arg(table).toUtf8().constData(),
+ -1, &select, nullptr);
+ while (select && sqlite3_step(select) == SQLITE_ROW) {
+ QStringList values;
+ for (int c = 0 ; c < sqlite3_column_count(select) ; ++c) {
+ const unsigned char *text = sqlite3_column_text(select, c);
+ values << (text ? QString::fromUtf8(reinterpret_cast(text)) : QStringLiteral("NULL"));
+ }
+ const QString row = table + QLatin1Char('|') + values.join(QLatin1Char('|'));
+ if (!row.contains(stamp)) rows << row;
+ }
+ sqlite3_finalize(select);
+ }
+ sqlite3_close(db);
+ return rows;
+ }
+
// The tables of the database in the .qetz @p path: the document's
// engineering data only, each fact once -- not QElectroTech's own
// project database, built from it when the project opens