@pilllesss/yorn 1.0.182 → 1.0.183

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @pilllesss/yorn might be problematic. Click here for more details.

Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/providers/data/.manifest.json +1 -1
  3. package/dist/skills/code-review/LICENSE +21 -0
  4. package/dist/skills/code-review/SKILL.md +233 -0
  5. package/dist/skills/code-review/assets/pr-review-template.md +137 -0
  6. package/dist/skills/code-review/assets/review-checklist.md +123 -0
  7. package/dist/skills/code-review/reference/angular.md +768 -0
  8. package/dist/skills/code-review/reference/architecture-review-guide.md +472 -0
  9. package/dist/skills/code-review/reference/c.md +890 -0
  10. package/dist/skills/code-review/reference/code-quality-universal.md +488 -0
  11. package/dist/skills/code-review/reference/code-review-best-practices.md +136 -0
  12. package/dist/skills/code-review/reference/common-bugs-checklist.md +302 -0
  13. package/dist/skills/code-review/reference/cpp.md +893 -0
  14. package/dist/skills/code-review/reference/cross-cutting/async-concurrency-patterns.md +515 -0
  15. package/dist/skills/code-review/reference/cross-cutting/error-handling-principles.md +492 -0
  16. package/dist/skills/code-review/reference/cross-cutting/n-plus-one-queries.md +309 -0
  17. package/dist/skills/code-review/reference/cross-cutting/sql-injection-prevention.md +308 -0
  18. package/dist/skills/code-review/reference/cross-cutting/xss-prevention.md +264 -0
  19. package/dist/skills/code-review/reference/csharp.md +525 -0
  20. package/dist/skills/code-review/reference/css-less-sass.md +661 -0
  21. package/dist/skills/code-review/reference/dart.md +670 -0
  22. package/dist/skills/code-review/reference/django.md +985 -0
  23. package/dist/skills/code-review/reference/fastapi.md +580 -0
  24. package/dist/skills/code-review/reference/go.md +993 -0
  25. package/dist/skills/code-review/reference/java.md +409 -0
  26. package/dist/skills/code-review/reference/java8.md +586 -0
  27. package/dist/skills/code-review/reference/kotlin.md +1018 -0
  28. package/dist/skills/code-review/reference/nestjs.md +593 -0
  29. package/dist/skills/code-review/reference/performance-review-guide.md +816 -0
  30. package/dist/skills/code-review/reference/php.md +684 -0
  31. package/dist/skills/code-review/reference/python.md +1073 -0
  32. package/dist/skills/code-review/reference/qt.md +757 -0
  33. package/dist/skills/code-review/reference/react.md +871 -0
  34. package/dist/skills/code-review/reference/ruby.md +964 -0
  35. package/dist/skills/code-review/reference/rust.md +846 -0
  36. package/dist/skills/code-review/reference/security-review-guide.md +494 -0
  37. package/dist/skills/code-review/reference/svelte.md +1064 -0
  38. package/dist/skills/code-review/reference/swift.md +936 -0
  39. package/dist/skills/code-review/reference/typescript.md +1016 -0
  40. package/dist/skills/code-review/reference/vue.md +924 -0
  41. package/dist/skills/code-review/reference/zig.md +440 -0
  42. package/dist/skills/code-review/scripts/pr-analyzer.py +435 -0
  43. package/dist/skills/code-review/scripts/test_pr_analyzer.py +380 -0
  44. package/dist/yorn.cjs +628 -628
  45. package/package.json +2 -2
@@ -0,0 +1,757 @@
1
+ # Qt Code Review Guide
2
+
3
+ > Code review guidelines focusing on object model, signals/slots, Model/View, QML, Qt6 migration, event loop, testing, and GUI performance. Examples based on Qt 5.15 / Qt 6.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Object Model & Memory Management](#object-model--memory-management)
8
+ - [Signals & Slots](#signals--slots)
9
+ - [Containers & Strings](#containers--strings)
10
+ - [Threads & Concurrency](#threads--concurrency)
11
+ - [GUI & Widgets](#gui--widgets)
12
+ - [Model/View Architecture](#modelview-architecture)
13
+ - [Meta-Object System](#meta-object-system)
14
+ - [QML / Qt Quick](#qml--qt-quick)
15
+ - [Qt5 → Qt6 Migration](#qt5--qt6-migration)
16
+ - [Testing](#testing)
17
+ - [Review Checklist](#review-checklist)
18
+
19
+ ---
20
+
21
+ ## Object Model & Memory Management
22
+
23
+ ### Use Parent-Child Ownership Mechanism
24
+ Qt's `QObject` hierarchy automatically manages memory. For `QObject`, prefer setting a parent object over manual `delete` or smart pointers.
25
+
26
+ ```cpp
27
+ // ❌ Manual management prone to memory leaks
28
+ QWidget* w = new QWidget();
29
+ QLabel* l = new QLabel();
30
+ l->setParent(w);
31
+ // ... If w is deleted, l is automatically deleted. But if w leaks, l also leaks.
32
+
33
+ // ✅ Specify parent in constructor
34
+ QWidget* w = new QWidget(this); // Owned by 'this'
35
+ QLabel* l = new QLabel(w); // Owned by 'w'
36
+ ```
37
+
38
+ ### Use Smart Pointers with QObject
39
+ If a `QObject` has no parent, use `QScopedPointer` or `std::unique_ptr` with a custom deleter (use `deleteLater` if cross-thread). Avoid `std::shared_ptr` for `QObject` unless necessary, as it confuses the parent-child ownership system.
40
+
41
+ ```cpp
42
+ // ✅ Scoped pointer for local/member QObject without parent
43
+ QScopedPointer<MyObject> obj(new MyObject());
44
+
45
+ // ✅ Safe pointer to prevent dangling pointers
46
+ QPointer<MyObject> safePtr = obj.data();
47
+ if (safePtr) {
48
+ safePtr->doSomething();
49
+ }
50
+ ```
51
+
52
+ ### Use `deleteLater()`
53
+ For asynchronous deletion, especially in slots or event handlers, use `deleteLater()` instead of `delete` to ensure pending events in the event loop are processed.
54
+
55
+ ```cpp
56
+ // ❌ Bad: delete in a slot may invalidate sender during signal emission
57
+ void MyWidget::onFinished() {
58
+ delete this; // UB: may be called from within a signal chain
59
+ }
60
+
61
+ // ✅ Good: safe deferred deletion
62
+ void MyWidget::onFinished() {
63
+ deleteLater();
64
+ }
65
+ ```
66
+
67
+ ### Avoid double ownership
68
+
69
+ ```cpp
70
+ // ❌ Bad: parent owns the dialog, but we also store it in unique_ptr
71
+ auto dialog = std::make_unique<QDialog>(this); // 'this' is parent AND unique_ptr owns it
72
+
73
+ // ✅ Good: parent owns it, raw pointer for access
74
+ auto* dialog = new QDialog(this);
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Signals & Slots
80
+
81
+ ### Prefer Function Pointer Syntax
82
+ Use compile-time checked syntax (Qt 5+).
83
+
84
+ ```cpp
85
+ // ❌ String-based (runtime check only, slower)
86
+ connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(updateValue(int)));
87
+
88
+ // ✅ Compile-time check
89
+ connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);
90
+ ```
91
+
92
+ ### Lambda connections — specify context object
93
+
94
+ ```cpp
95
+ // ❌ Bad: lambda captures `this` raw; crashes if object is deleted
96
+ connect(timer, &QTimer::timeout, [this]() {
97
+ update(); // crashes if 'this' was destroyed
98
+ });
99
+
100
+ // ✅ Good: context object disconnects automatically on destruction
101
+ connect(timer, &QTimer::timeout, this, [this]() {
102
+ update();
103
+ });
104
+ ```
105
+
106
+ ### Connection Types
107
+ Be explicit or aware of connection types when crossing threads.
108
+ - `Qt::AutoConnection` (Default): Direct if same thread, Queued if different thread.
109
+ - `Qt::QueuedConnection`: Always posts event (thread-safe across threads).
110
+ - `Qt::DirectConnection`: Immediate call (dangerous if accessing non-thread-safe data across threads).
111
+
112
+ ### Avoid Loops
113
+ Check logic that might cause infinite signal loops (e.g., `valueChanged` -> `setValue` -> `valueChanged`). Block signals or check for equality before setting values.
114
+
115
+ ```cpp
116
+ void MyClass::setValue(int v) {
117
+ if (m_value == v) return; // ✅ Good: Break loop
118
+ m_value = v;
119
+ emit valueChanged(v);
120
+ }
121
+ ```
122
+
123
+ ### Disconnect when appropriate
124
+
125
+ ```cpp
126
+ // ✅ Good: explicit disconnect before changing target
127
+ disconnect(oldSource, &Source::data, this, &Receiver::onData);
128
+ connect(newSource, &Source::data, this, &Receiver::onData);
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Containers & Strings
134
+
135
+ ### QString Efficiency
136
+ - Use `QStringLiteral("...")` for compile-time string creation to avoid runtime allocation.
137
+ - Use `QLatin1String` for comparison with ASCII literals (in Qt 5).
138
+ - Prefer `arg()` for formatting (or `QStringBuilder`'s `%` operator).
139
+
140
+ ```cpp
141
+ // ❌ Runtime conversion
142
+ if (str == "test") ...
143
+
144
+ // ✅ Prefer QLatin1String for comparison with ASCII literals (in Qt 5)
145
+ if (str == QLatin1String("test")) ... // Qt 5
146
+ if (str == u"test"_s) ... // Qt 6
147
+ ```
148
+
149
+ ### Container Selection
150
+ - **Qt 6**: `QList` is now the default choice (unified with `QVector`).
151
+ - **Qt 5**: Prefer `QVector` over `QList` for contiguous memory and cache performance, unless stable references are needed.
152
+ - Be aware of Implicit Sharing (Copy-on-Write). Passing containers by value is cheap *until* modified. Use `const &` for read-only access.
153
+
154
+ ```cpp
155
+ // ❌ Forces deep copy if function modifies 'list'
156
+ void process(QVector<int> list) {
157
+ list[0] = 1;
158
+ }
159
+
160
+ // ✅ Read-only reference
161
+ void process(const QVector<int>& list) { ... }
162
+ ```
163
+
164
+ ### Use constBegin/constEnd for read-only iteration
165
+
166
+ ```cpp
167
+ // ❌ Bad: begin()/end() may trigger detach
168
+ for (auto it = list.begin(); it != list.end(); ++it) {
169
+ qDebug() << *it;
170
+ }
171
+
172
+ // ✅ Good: const iteration avoids detach
173
+ for (auto it = list.constBegin(); it != list.constEnd(); ++it) {
174
+ qDebug() << *it;
175
+ }
176
+
177
+ // ✅ Best: range-based for with const ref (Qt 5.7+)
178
+ for (const auto& item : list) {
179
+ qDebug() << item;
180
+ }
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Threads & Concurrency
186
+
187
+ ### Subclassing QThread vs Worker Object
188
+ Prefer the "Worker Object" pattern over subclassing `QThread` implementation details.
189
+
190
+ ```cpp
191
+ // ❌ Business logic inside QThread::run()
192
+ class MyThread : public QThread {
193
+ void run() override { ... }
194
+ };
195
+
196
+ // ✅ Worker object moved to thread
197
+ QThread* thread = new QThread;
198
+ Worker* worker = new Worker;
199
+ worker->moveToThread(thread);
200
+ connect(thread, &QThread::started, worker, &Worker::process);
201
+ connect(thread, &QThread::finished, worker, &QObject::deleteLater);
202
+ thread->start();
203
+ ```
204
+
205
+ ### GUI Thread Safety
206
+ **NEVER** access UI widgets (`QWidget` and subclasses) from a background thread. Use signals/slots to communicate updates to the main thread.
207
+
208
+ ```cpp
209
+ // ❌ Bad: accessing widget from worker thread
210
+ void Worker::onResult(Data data) {
211
+ label->setText(data.toString()); // CRASH: not in GUI thread
212
+ }
213
+
214
+ // ✅ Good: signal to GUI thread
215
+ void Worker::onResult(Data data) {
216
+ emit resultReady(data); // connected via QueuedConnection
217
+ }
218
+ // In main thread:
219
+ connect(worker, &Worker::resultReady, this, [this](const Data& d) {
220
+ label->setText(d.toString());
221
+ });
222
+ ```
223
+
224
+ ### QtConcurrent for simple parallelism
225
+
226
+ ```cpp
227
+ // ✅ Good: simple parallel computation
228
+ auto future = QtConcurrent::run([data]() {
229
+ return heavyComputation(data);
230
+ });
231
+
232
+ // ✅ Good: map-reduce pattern
233
+ auto results = QtConcurrent::mappedReduced(
234
+ inputList,
235
+ [](const Item& item) { return process(item); },
236
+ [](int& result, int value) { result += value; }
237
+ );
238
+ ```
239
+
240
+ ---
241
+
242
+ ## GUI & Widgets
243
+
244
+ ### Logic Separation
245
+ Keep business logic out of UI classes (`MainWindow`, `Dialog`). UI classes should only handle display and user input forwarding.
246
+
247
+ ### Layouts
248
+ Avoid fixed sizes (`setGeometry`, `resize`). Use layouts (`QVBoxLayout`, `QGridLayout`) to handle different DPIs and window resizing gracefully.
249
+
250
+ ### Blocking Event Loop
251
+ Never execute long-running operations on the main thread (freezes GUI).
252
+ - **Bad**: `Sleep()`, `while(busy)`, synchronous network calls.
253
+ - **Good**: `QProcess`, `QThread`, `QtConcurrent`, or asynchronous APIs (`QNetworkAccessManager`).
254
+
255
+ ### High-DPI scaling
256
+
257
+ ```cpp
258
+ // ✅ Qt 5: enable high-DPI scaling
259
+ QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
260
+
261
+ // ✅ Qt 6: enabled by default, but verify icons and custom painting scale correctly
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Model/View Architecture
267
+
268
+ ### Subclass QAbstractItemModel correctly
269
+
270
+ When implementing a custom model, the following methods are **required**:
271
+
272
+ ```cpp
273
+ class TaskModel : public QAbstractTableModel {
274
+ Q_OBJECT
275
+ public:
276
+ int rowCount(const QModelIndex& parent = {}) const override {
277
+ if (parent.isValid()) return 0; // table model has no tree
278
+ return m_tasks.size();
279
+ }
280
+
281
+ int columnCount(const QModelIndex& parent = {}) const override {
282
+ if (parent.isValid()) return 0;
283
+ return 3; // title, priority, status
284
+ }
285
+
286
+ QVariant data(const QModelIndex& index, int role) const override {
287
+ if (!index.isValid() || index.row() >= m_tasks.size())
288
+ return {};
289
+
290
+ if (role == Qt::DisplayRole) {
291
+ switch (index.column()) {
292
+ case 0: return m_tasks[index.row()].title;
293
+ case 1: return m_tasks[index.row()].priority;
294
+ case 2: return m_tasks[index.row()].status;
295
+ }
296
+ }
297
+ return {};
298
+ }
299
+
300
+ // Required for headers
301
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override {
302
+ if (role != Qt::DisplayRole) return {};
303
+ if (orientation == Qt::Horizontal) {
304
+ switch (section) {
305
+ case 0: return "Title";
306
+ case 1: return "Priority";
307
+ case 2: return "Status";
308
+ }
309
+ }
310
+ return section + 1; // row numbers
311
+ }
312
+
313
+ private:
314
+ QVector<Task> m_tasks;
315
+ };
316
+ ```
317
+
318
+ ### Notify the view of changes
319
+
320
+ ```cpp
321
+ // ❌ Bad: modifying data without notifying the view
322
+ void TaskModel::addTask(const Task& task) {
323
+ m_tasks.append(task); // view doesn't know about the change
324
+ }
325
+
326
+ // ✅ Good: emit proper signals
327
+ void TaskModel::addTask(const Task& task) {
328
+ beginInsertRows({}, m_tasks.size(), m_tasks.size());
329
+ m_tasks.append(task);
330
+ endInsertRows();
331
+ }
332
+
333
+ void TaskModel::updateStatus(int row, const QString& status) {
334
+ m_tasks[row].status = status;
335
+ emit dataChanged(index(row, 2), index(row, 2), {Qt::DisplayRole});
336
+ }
337
+
338
+ void TaskModel::clearAll() {
339
+ beginResetModel();
340
+ m_tasks.clear();
341
+ endResetModel();
342
+ }
343
+ ```
344
+
345
+ ### Delegate pattern for custom rendering
346
+
347
+ ```cpp
348
+ class PriorityDelegate : public QStyledItemDelegate {
349
+ Q_OBJECT
350
+ public:
351
+ void paint(QPainter* painter, const QStyleOptionViewItem& option,
352
+ const QModelIndex& index) const override {
353
+ QStyleOptionViewItem opt = option;
354
+ initStyleOption(&opt, index);
355
+
356
+ // Color-code by priority
357
+ QString priority = index.data().toString();
358
+ if (priority == "High") {
359
+ opt.backgroundBrush = QColor("#ffcccc");
360
+ } else if (priority == "Low") {
361
+ opt.backgroundBrush = QColor("#ccffcc");
362
+ }
363
+
364
+ QStyledItemDelegate::paint(painter, opt, index);
365
+ }
366
+ };
367
+
368
+ // Usage:
369
+ tableView->setItemDelegateForColumn(1, new PriorityDelegate(this));
370
+ ```
371
+
372
+ ### Performance with large datasets
373
+
374
+ - Use `beginInsertRows`/`endInsertRows` for batch inserts, not one row at a time.
375
+ - For 100K+ rows, consider `QSortFilterProxyModel` for filtering instead of re-querying.
376
+ - Use `model()->fetchMore()` for lazy loading / pagination.
377
+ - Avoid `Qt::UserRole + N` with heavy objects; use a lightweight key and look up externally.
378
+
379
+ ---
380
+
381
+ ## Meta-Object System
382
+
383
+ ### Properties & Enums
384
+ Use `Q_PROPERTY` for values exposed to QML or needing introspection.
385
+ Use `Q_ENUM` to enable string conversion for enums.
386
+
387
+ ```cpp
388
+ class MyObject : public QObject {
389
+ Q_OBJECT
390
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
391
+ public:
392
+ enum State { Idle, Running };
393
+ Q_ENUM(State)
394
+ // ...
395
+ };
396
+ ```
397
+
398
+ ### qobject_cast
399
+ Use `qobject_cast<T*>` for QObjects instead of `dynamic_cast`. It is faster and doesn't require RTTI.
400
+
401
+ ### Q_GADGET for value types
402
+
403
+ ```cpp
404
+ // ✅ Good: introspection without QObject overhead
405
+ struct Coordinate {
406
+ Q_GADGET
407
+ Q_PROPERTY(double x MEMBER x)
408
+ Q_PROPERTY(double y MEMBER y)
409
+ public:
410
+ double x = 0.0;
411
+ double y = 0.0;
412
+ };
413
+ Q_DECLARE_METATYPE(Coordinate)
414
+ ```
415
+
416
+ ---
417
+
418
+ ## QML / Qt Quick
419
+
420
+ ### C++/QML boundary design
421
+
422
+ ```cpp
423
+ // ✅ Good: expose C++ model to QML via context property (Qt 5) or QML_SINGLETON (Qt 6)
424
+
425
+ // Qt 6: QML_ELEMENT + QML_SINGLETON
426
+ class AppSettings : public QObject {
427
+ Q_OBJECT
428
+ QML_ELEMENT
429
+ QML_SINGLETON
430
+ Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
431
+ public:
432
+ QString theme() const { return m_theme; }
433
+ void setTheme(const QString& t) {
434
+ if (m_theme != t) {
435
+ m_theme = t;
436
+ emit themeChanged();
437
+ }
438
+ }
439
+ signals:
440
+ void themeChanged();
441
+ private:
442
+ QString m_theme;
443
+ };
444
+ ```
445
+
446
+ ### QML performance best practices
447
+
448
+ ```qml
449
+ // ❌ Bad: JavaScript in onCompleted blocks UI thread
450
+ Component.onCompleted: {
451
+ for (var i = 0; i < 10000; i++) {
452
+ model.append({"value": i}); // slow, blocks rendering
453
+ }
454
+ }
455
+
456
+ // ✅ Good: use C++ model, or WorkerScript for heavy JS
457
+ // Prefer C++ QAbstractListModel for large datasets
458
+ ```
459
+
460
+ ```qml
461
+ // ❌ Bad: frequent property bindings cause re-evaluation
462
+ Rectangle {
463
+ width: parent.width * 0.8 + someComplexCalc()
464
+ height: parent.height * 0.6 + anotherCalc()
465
+ }
466
+
467
+ // ✅ Good: minimize binding complexity
468
+ Rectangle {
469
+ width: parent.width * 0.8
470
+ height: parent.height * 0.6
471
+ }
472
+ ```
473
+
474
+ ### QML object lifecycle
475
+
476
+ - QML-created objects are owned by the QML engine.
477
+ - `Qt.createComponent()` + `createObject()` — caller manages lifetime.
478
+ - Use `Loader` for lazy instantiation of heavy components.
479
+ - `property var myObj: QtObject {}` — the QML engine owns it.
480
+
481
+ ```qml
482
+ // ✅ Good: Loader for conditional heavy UI
483
+ Loader {
484
+ id: detailLoader
485
+ active: selectedItem !== null
486
+ sourceComponent: active ? detailComponent : null
487
+ }
488
+ ```
489
+
490
+ ---
491
+
492
+ ## Qt5 → Qt6 Migration
493
+
494
+ ### Key breaking changes
495
+
496
+ | Qt 5 | Qt 6 | Notes |
497
+ |------|------|-------|
498
+ | `QList` ≠ `QVector` | `QList` = `QVector` | Unified; QList is now QVector internally |
499
+ | `QStringRef` | `QStringView` | QStringView is non-owning, more like string_view |
500
+ | `QLatin1String` | `QLatin1StringView` | Or use `u"..."_s` string literals |
501
+ | `QTextStream(stream)` | `QTextStream(&string)` | Constructor changes |
502
+ | `QMouseEvent::pos()` | `QMouseEvent::position()` | Returns QPointF instead of QPoint |
503
+ | `QWheelEvent::delta()` | `QWheelEvent::angleDelta()` | Already deprecated in Qt 5 |
504
+ | `QComboBox::activated(int)` | `QComboBox::textActivated(QString)` | Overload disambiguation |
505
+
506
+ ### CMake replaces qmake
507
+
508
+ ```cmake
509
+ # ✅ Qt 6 CMakeLists.txt
510
+ cmake_minimum_required(VERSION 3.16)
511
+ project(MyApp LANGUAGES CXX)
512
+
513
+ set(CMAKE_CXX_STANDARD 17)
514
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
515
+ set(CMAKE_AUTOMOC ON)
516
+ set(CMAKE_AUTORCC ON)
517
+
518
+ find_package(Qt6 REQUIRED COMPONENTS Widgets Quick Core)
519
+
520
+ qt_add_executable(MyApp
521
+ main.cpp
522
+ MainWindow.cpp
523
+ MainWindow.h
524
+ resources.qrc
525
+ )
526
+
527
+ target_link_libraries(MyApp PRIVATE
528
+ Qt6::Widgets
529
+ Qt6::Quick
530
+ Qt6::Core
531
+ )
532
+ ```
533
+
534
+ ### Qt6 new APIs and improvements
535
+
536
+ ```cpp
537
+ // ✅ Qt 6: QStringView instead of QStringRef
538
+ void process(QStringView sv); // non-owning, efficient
539
+
540
+ // ✅ Qt 6: QCalendar API for date handling
541
+ QCalendar cal(QCalendar::System::Gregorian);
542
+ QDate date = cal.dateFromParts(2024, 3, 15);
543
+
544
+ // ✅ Qt 6: Qt Concurrent improvements
545
+ auto future = QtConcurrent::run(QThreadPool::globalInstance(),
546
+ []() { return heavyWork(); });
547
+
548
+ // ✅ Qt 6: Compare API for containers
549
+ QList<int> a = {1, 2, 3};
550
+ QList<int> b = {1, 2, 3};
551
+ bool eq = a == b; // works correctly in Qt 6
552
+ ```
553
+
554
+ ### Migration checklist
555
+
556
+ - [ ] Replace `qmake` with `CMake` (or use `qt-cmake`)
557
+ - [ ] Replace `QStringRef` with `QStringView`
558
+ - [ ] Replace deprecated event accessors (`pos()` → `position()`)
559
+ - [ ] Update signal/slot connections for overloaded signals (use `qOverload`)
560
+ - [ ] Verify `QList`/`QVector` interchangeability
561
+ - [ ] Test with Qt 6 compatibility module: `find_package(Qt6 COMPONENTS Core5Compat)`
562
+
563
+ ---
564
+
565
+ ## Testing
566
+
567
+ ### QTest framework
568
+
569
+ ```cpp
570
+ #include <QtTest>
571
+ #include "parser.h"
572
+
573
+ class TestParser : public QObject {
574
+ Q_OBJECT
575
+ private slots:
576
+ void testEmptyInput() {
577
+ Parser p("");
578
+ QVERIFY(p.nextToken().isNull());
579
+ }
580
+
581
+ void testIntegerToken() {
582
+ Parser p("42");
583
+ auto token = p.nextToken();
584
+ QCOMPARE(token.type(), Token::Integer);
585
+ QCOMPARE(token.value().toInt(), 42);
586
+ }
587
+
588
+ void testNegativeNumber() {
589
+ Parser p("-7");
590
+ auto token = p.nextToken();
591
+ QCOMPARE(token.value().toInt(), -7);
592
+ }
593
+
594
+ // Data-driven test
595
+ void testValidTokens_data() {
596
+ QTest::addColumn<QString>("input");
597
+ QTest::addColumn<int>("expectedType");
598
+
599
+ QTest::newRow("integer") << "42" << static_cast<int>(Token::Integer);
600
+ QTest::newRow("string") << "\"hello\"" << static_cast<int>(Token::String);
601
+ QTest::newRow("operator") << "+" << static_cast<int>(Token::Operator);
602
+ }
603
+
604
+ void testValidTokens() {
605
+ QFETCH(QString, input);
606
+ QFETCH(int, expectedType);
607
+
608
+ Parser p(input);
609
+ auto token = p.nextToken();
610
+ QCOMPARE(token.type(), static_cast<Token::Type>(expectedType));
611
+ }
612
+ };
613
+
614
+ QTEST_MAIN(TestParser)
615
+ #include "test_parser.moc"
616
+ ```
617
+
618
+ ### GUI testing with QTest
619
+
620
+ ```cpp
621
+ class TestLoginDialog : public QObject {
622
+ Q_OBJECT
623
+ private slots:
624
+ void testLoginButtonDisabledWhenEmpty() {
625
+ LoginDialog dialog;
626
+ dialog.show();
627
+ QVERIFY(QTest::qWaitForWindowExposed(&dialog));
628
+
629
+ // Initially, login button should be disabled
630
+ QPushButton* loginBtn = dialog.findChild<QPushButton*>("loginButton");
631
+ QVERIFY(loginBtn != nullptr);
632
+ QVERIFY(!loginBtn->isEnabled());
633
+ }
634
+
635
+ void testLoginEnabledAfterInput() {
636
+ LoginDialog dialog;
637
+ dialog.show();
638
+ QVERIFY(QTest::qWaitForWindowExposed(&dialog));
639
+
640
+ QLineEdit* userField = dialog.findChild<QLineEdit*>("usernameField");
641
+ QLineEdit* passField = dialog.findChild<QLineEdit*>("passwordField");
642
+
643
+ QTest::keyClicks(userField, "alice");
644
+ QTest::keyClicks(passField, "secret123");
645
+
646
+ QPushButton* loginBtn = dialog.findChild<QPushButton*>("loginButton");
647
+ QVERIFY(loginBtn->isEnabled());
648
+ }
649
+
650
+ void testSubmitOnEnter() {
651
+ LoginDialog dialog;
652
+ dialog.show();
653
+ QVERIFY(QTest::qWaitForWindowExposed(&dialog));
654
+
655
+ QLineEdit* userField = dialog.findChild<QLineEdit*>("usernameField");
656
+ QTest::keyClicks(userField, "alice");
657
+ QTest::keyClick(userField, Qt::Key_Return);
658
+
659
+ // Verify the dialog emitted the accepted signal
660
+ QTRY_COMPARE(dialog.result(), static_cast<int>(QDialog::Accepted));
661
+ }
662
+ };
663
+ ```
664
+
665
+ ### Mock Qt objects for unit testing
666
+
667
+ ```cpp
668
+ // ✅ Good: inject dependencies for testability
669
+ class NetworkService {
670
+ public:
671
+ virtual ~NetworkService() = default;
672
+ virtual QJsonObject fetchUser(int id) = 0;
673
+ };
674
+
675
+ class MockNetworkService : public NetworkService {
676
+ public:
677
+ QJsonObject fetchUser(int id) override {
678
+ return m_responses.value(id, {});
679
+ }
680
+ void setResponse(int id, const QJsonObject& json) {
681
+ m_responses[id] = json;
682
+ }
683
+ private:
684
+ QHash<int, QJsonObject> m_responses;
685
+ };
686
+
687
+ // In test:
688
+ void testProfileDisplay() {
689
+ MockNetworkService mock;
690
+ mock.setResponse(1, {{"name", "Alice"}, {"role", "admin"}});
691
+
692
+ ProfileController controller(&mock);
693
+ controller.loadProfile(1);
694
+ QCOMPARE(controller.name(), "Alice");
695
+ QCOMPARE(controller.role(), "admin");
696
+ }
697
+ ```
698
+
699
+ ### CI integration
700
+
701
+ ```bash
702
+ # Qt 6 test runner
703
+ mkdir build && cd build
704
+ cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON
705
+ cmake --build .
706
+ ctest --output-on-failure
707
+
708
+ # With Xvfb for GUI tests on headless CI
709
+ xvfb-run -a ctest --output-on-failure
710
+ ```
711
+
712
+ ---
713
+
714
+ ## Review Checklist
715
+
716
+ ### Memory
717
+ - [ ] Is parent-child relationship correct? Are dangling pointers avoided (using `QPointer`)?
718
+ - [ ] No double ownership (parent + smart pointer)
719
+ - [ ] `deleteLater()` used instead of `delete` in slots
720
+
721
+ ### Signals & Slots
722
+ - [ ] Function pointer syntax used (compile-time checked)
723
+ - [ ] Lambda connections have context object for auto-disconnect
724
+ - [ ] No signal loops (guard with equality check or blockSignals)
725
+ - [ ] Proper disconnect when changing signal sources
726
+
727
+ ### Threads
728
+ - [ ] Is UI accessed only from main thread?
729
+ - [ ] Are long tasks offloaded (QThread worker, QtConcurrent)?
730
+ - [ ] Worker object pattern preferred over QThread subclassing
731
+ - [ ] Proper cleanup: thread quit + wait before delete
732
+
733
+ ### Strings & Containers
734
+ - [ ] `QStringLiteral` or `u"..."_s` used for compile-time strings
735
+ - [ ] `const &` used for read-only container access
736
+ - [ ] No implicit detach in loops (use const iterators or range-for with const ref)
737
+
738
+ ### Model/View
739
+ - [ ] begin/end Insert/Remove/Reset signals emitted correctly
740
+ - [ ] dataChanged emitted for individual item updates
741
+ - [ ] Delegate used for custom rendering (not subclassing view)
742
+
743
+ ### QML
744
+ - [ ] C++/QML boundary uses QML_ELEMENT (Qt 6) or registered types
745
+ - [ ] Heavy computation not in QML JS
746
+ - [ ] Loader used for conditional/lazy component instantiation
747
+
748
+ ### Testing
749
+ - [ ] QTest unit tests for core logic
750
+ - [ ] GUI tests use QTest::keyClicks / qWaitForWindowExposed
751
+ - [ ] Dependencies injected for mockability
752
+ - [ ] Tests run in CI (with Xvfb for GUI tests)
753
+
754
+ ### Style
755
+ - [ ] Naming conventions (camelCase for methods, PascalCase for classes)
756
+ - [ ] Resources loaded from `.qrc`
757
+ - [ ] `Q_OBJECT` macro present in all QObject subclasses