First Commit

This commit is contained in:
xiaolinquan committed 2026-11-06 01:04:35 +08:00
commit 3796ec5cd2
146 files changed
+4825

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.16)
project(UnitConverter VERSION 1.0 LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
if(QT_VERSION_MAJOR EQUAL 5 AND Qt5Core_VERSION VERSION_LESS 5.14.2)
message(FATAL_ERROR "Qt 5.14.2 or newer is required.")
endif()
if(QT_VERSION_MAJOR EQUAL 6)
set(CMAKE_CXX_STANDARD 17)
endif()
if(MSVC)
add_compile_options(/utf-8)
else()
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
add_executable(UnitConverter WIN32 main.cpp appearance.h mainwindow.cpp mainwindow.h conversion.cpp conversion.h mainwindow.ui)
target_link_libraries(UnitConverter PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
option(BUILD_TEACHING_TESTS "Build teaching project tests" OFF)
if(BUILD_TEACHING_TESTS)
enable_testing()
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Test)
add_executable(test_UnitConverter tests/test_UnitConverter.cpp mainwindow.cpp mainwindow.h
conversion.cpp conversion.h mainwindow.ui)
target_include_directories(test_UnitConverter PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(test_UnitConverter PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Test)
add_test(NAME UnitConverter COMMAND test_UnitConverter -platform offscreen)
endif()
+59
View File
@@ -0,0 +1,59 @@
# 项目一:单位换算器
适合第2—3章讲解信号槽、组件访问和函数分工,第4章可继续练习下拉框与字符串处理。
## 运行后试什么
初始输入为 25,源单位为摄氏度,目标单位为华氏度。点击“换算”,应显示 77 °F,并在下方显示公式。也可以在输入框内按 Enter。
切换到长度后,默认将米换成厘米。输入 1,结果应为 100 cm。“交换单位”只交换源单位与目标单位,输入值保持不变。修改输入或单位会清空旧结果,防止把上次的答案当成当前答案。
支持摄氏度、华氏度、开尔文,以及毫米、厘米、米、千米、英寸和英尺。结果最多显示 12 位有效数字。
## 课堂任务
第一步只保留温度输入、换算按钮和结果框。让学生完成摄氏度到华氏度的换算,并解释输入框返回的是字符串,计算需要数值。
第二步加入返回值检查。分别输入空字符串、abc 和 25.5,观察程序怎样决定是否继续计算。当前工程用完整字符串的格式检查配合 toDouble,支持小数和科学计数法,不接受千位分隔符。
第三步加入源单位和目标单位。先统一到摄氏度,再计算目标温度。让学生画出华氏度到开尔文的两步过程,避免只背诵一个总公式。
第四步加入长度换算。单位比例写在数组中,先解释数组下标与下拉框顺序的对应关系,再讨论增加一个单位时需要修改哪些位置。
## 一次换算怎样完成
1. convertButton 发出 clicked 信号,调用 convertValue。
2. 主窗口读取 inputEdit 的文本和两个下拉框的索引。
3. Conversion::convert 检查输入,计算结果,返回 Result。
4. 主窗口根据 Result::ok 显示结果或错误原因。
5. 计算成功后允许复制;输入变化后立即禁用复制并清除旧结果。
Conversion::convert 不直接操作输入框或标签,因此可以使用不同界面调用,也可以单独测试。
## 需要解释的条件
- 温度不能低于绝对零度。摄氏度下限为 −273.15,华氏度下限为 −459.67,开尔文下限为 0。
- 边界比较保留极小的浮点误差余量,防止换算时的舍入把绝对零度判为非法值。
- 本工具中的长度表示非负长度,不表示带方向的坐标位移。
- 输入可以合法,但结果仍可能溢出。输入检查和结果检查分别负责两个阶段。
- 显示的有效数字有限,程序不承诺任意精度计算。
## 学生练习
1. 增加“码”,已知 1 yd = 0.9144 m。检查它与米、英尺之间的换算。
2. 增加“使用本次结果继续换算”按钮,说明它与“交换单位”的区别。
3. 为结果增加可选择的显示精度,并解释显示精度为什么不等于计算精度。
## 验收用例
| 操作 | 预期 |
|---|---|
| 0 °C → °F | 32 |
| 212 °F → °C | 100 |
| −459.67 °F → K | 0 |
| −274 °C → K | 显示低于绝对零度的提示 |
| 1 in → cm | 2.54 |
| 1 ft → m | 0.3048 |
| 输入 12abc、nan 或 1,000 | 拒绝计算 |
| 算出结果后修改输入 | 旧结果清空,复制按钮不可用 |
@@ -0,0 +1,10 @@
QT += widgets
CONFIG += c++14
greaterThan(QT_MAJOR_VERSION, 5): CONFIG += c++17
TEMPLATE = app
TARGET = UnitConverter
SOURCES += main.cpp mainwindow.cpp conversion.cpp
HEADERS += mainwindow.h conversion.h
FORMS += mainwindow.ui
msvc: QMAKE_CXXFLAGS += /utf-8
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <QApplication>
#include <QFont>
#include <QStyleFactory>
inline void applyAppearance(QApplication &app)
{
app.setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
app.setFont(QFont(QStringLiteral("Microsoft YaHei UI"), 11));
app.setStyleSheet(QStringLiteral(
"QMainWindow { background: #f5f7fb; }"
"QLabel { color: #23364c; }"
"QLabel#titleLabel { font-size: 27px; font-weight: bold; color: #173b63; }"
"QLabel#subtitleLabel, QLabel#helpLabel { color: #52657a; }"
"QGroupBox { background: white; border: 1px solid #d6e0eb;"
" border-radius: 8px; margin-top: 12px; padding: 18px 12px 12px; }"
"QGroupBox::title { subcontrol-origin: margin; left: 12px; padding: 0 6px; }"
"QLineEdit, QSpinBox, QComboBox { min-height: 32px; padding: 3px 8px; }"
"QLineEdit, QSpinBox, QComboBox, QPlainTextEdit, QListWidget"
" { background: white; color: #23364c; }"
"QPushButton { min-height: 34px; padding: 4px 14px; }"
"QPushButton#convertButton, QPushButton#startButton, QPushButton#drawButton,"
" QPushButton#applyButton, QPushButton#groupsButton { background: #255c93;"
" color: white; border: 1px solid #255c93; border-radius: 5px; }"
"QPushButton:disabled, QPushButton#convertButton:disabled,"
" QPushButton#startButton:disabled, QPushButton#drawButton:disabled,"
" QPushButton#applyButton:disabled, QPushButton#groupsButton:disabled"
" { color: #8995a3; background: #e6ebf1; border-color: #d6e0eb; }"
"QLabel#statusLabel { color: #185376; }"
"QLineEdit#resultEdit { font-size: 23px; min-height: 45px; color: #175e53; }"
"QLabel#timeLabel { font: bold 76px 'Consolas'; color: #173b63; }"
"QProgressBar { border: 1px solid #d6e0eb; border-radius: 6px; height: 14px; }"
"QProgressBar::chunk { background: #2b8a7d; border-radius: 5px; }"));
}
+94
View File
@@ -0,0 +1,94 @@
#include "conversion.h"
#include <QRegularExpression>
#include <cmath>
namespace Conversion {
QStringList units(Category category)
{
if (category == Category::Temperature)
return {QStringLiteral("摄氏度 °C"), QStringLiteral("华氏度 °F"),
QStringLiteral("开尔文 K")};
return {QStringLiteral("毫米 mm"), QStringLiteral("厘米 cm"),
QStringLiteral("米 m"), QStringLiteral("千米 km"),
QStringLiteral("英寸 in"), QStringLiteral("英尺 ft")};
}
Result convert(const QString &text, Category category, int from, int to)
{
Result result;
const QString input = text.trimmed();
// 先检查完整输入,避免把“12abc”误当成有效数值。
static const QRegularExpression number(
QStringLiteral("^[+-]?(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)(?:[eE][+-]?[0-9]+)?$"));
if (!number.match(input).hasMatch()) {
result.error = QStringLiteral("请输入完整的数值,例如 25、-10.5 或 1e3;小数点使用英文句点。");
return result;
}
bool ok = false;
const double value = input.toDouble(&ok);
if (!ok || !std::isfinite(value)) {
result.error = QStringLiteral("输入超出了可计算的数值范围,请减小数值。");
return result;
}
const QStringList names = units(category);
if (from < 0 || to < 0 || from >= names.size() || to >= names.size()) {
result.error = QStringLiteral("请选择有效的单位。");
return result;
}
if (category == Category::Temperature) {
// 先统一为摄氏度,再换算为目标单位,避免为每对单位各写一套公式。
double celsius = value;
QString first;
if (from == 1) {
celsius = (value - 32.0) / 1.8;
first = QStringLiteral("先换成摄氏度:C = (F − 32) ÷ 1.8。");
} else if (from == 2) {
celsius = value - 273.15;
first = QStringLiteral("先换成摄氏度:C = K − 273.15。");
} else {
first = QStringLiteral("输入已经是摄氏度,可直接作为中间值。");
}
if (celsius < -273.15 - 1e-9) {
result.error = QStringLiteral("温度不能低于绝对零度:−273.15 °C / −459.67 °F / 0 K。");
return result;
}
// 允许边界处的浮点舍入误差,避免把绝对零度误判为非法输入。
if (celsius < -273.15)
celsius = -273.15;
QString second;
if (to == 1) {
result.value = celsius * 1.8 + 32.0;
second = QStringLiteral("再换成华氏度:F = C × 1.8 + 32。");
} else if (to == 2) {
result.value = celsius + 273.15;
second = QStringLiteral("再换成开尔文:K = C + 273.15。");
} else {
result.value = celsius;
second = QStringLiteral("目标是摄氏度,中间值就是结果。");
}
result.explanation = first + QStringLiteral("\n") + second;
} else {
if (value < 0.0) {
result.error = QStringLiteral("本工具换算的是长度,输入值不能为负数。");
return result;
}
const double metersPerUnit[] = {0.001, 0.01, 1.0, 1000.0, 0.0254, 0.3048};
result.value = value * (metersPerUnit[from] / metersPerUnit[to]);
result.explanation =
QStringLiteral("以米为统一单位:结果 = 输入值 × 源单位的米数 ÷ 目标单位的米数。\n"
"本次计算:%1 × %2 ÷ %3。")
.arg(input)
.arg(metersPerUnit[from], 0, 'g', 12)
.arg(metersPerUnit[to], 0, 'g', 12);
}
if (!std::isfinite(result.value)) {
result.error = QStringLiteral("换算结果超出了可显示的数值范围。");
return result;
}
if (result.value == 0.0)
result.value = 0.0; // 避免显示 -0。
result.ok = true;
return result;
}
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <QString>
#include <QStringList>
namespace Conversion {
enum class Category { Temperature, Length };
struct Result {
bool ok = false;
double value = 0.0;
QString explanation;
QString error;
};
QStringList units(Category category);
Result convert(const QString &text, Category category, int from, int to);
}
+19
View File
@@ -0,0 +1,19 @@
#include "mainwindow.h"
#include "appearance.h"
#include <QApplication>
#include <QFont>
#include <QStyleFactory>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QApplication app(argc, argv);
applyAppearance(app);
MainWindow window;
window.show();
return app.exec();
}
+83
View File
@@ -0,0 +1,83 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "conversion.h"
#include <QClipboard>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->categoryCombo->addItems({tr("温度"), tr("长度")});
connect(ui->categoryCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &MainWindow::changeCategory);
connect(ui->convertButton, &QPushButton::clicked, this, &MainWindow::convertValue);
connect(ui->inputEdit, &QLineEdit::returnPressed, this, &MainWindow::convertValue);
connect(ui->inputEdit, &QLineEdit::textChanged, this, &MainWindow::clearResult);
connect(ui->fromCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &MainWindow::clearResult);
connect(ui->toCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &MainWindow::clearResult);
connect(ui->swapButton, &QPushButton::clicked, this, [this] {
const int previousFrom = ui->fromCombo->currentIndex();
ui->fromCombo->setCurrentIndex(ui->toCombo->currentIndex());
ui->toCombo->setCurrentIndex(previousFrom);
ui->inputEdit->setFocus();
});
connect(ui->clearButton, &QPushButton::clicked, this, [this] {
ui->inputEdit->clear();
clearResult();
ui->inputEdit->setFocus();
});
connect(ui->copyButton, &QPushButton::clicked, this, [this] {
QApplication::clipboard()->setText(ui->resultEdit->text());
ui->statusLabel->setText(tr("结果已复制。"));
});
changeCategory();
ui->inputEdit->setText(QStringLiteral("25"));
}
MainWindow::~MainWindow() { delete ui; }
void MainWindow::changeCategory()
{
const auto category = ui->categoryCombo->currentIndex() == 0
? Conversion::Category::Temperature : Conversion::Category::Length;
const QStringList names = Conversion::units(category);
ui->fromCombo->clear();
ui->toCombo->clear();
ui->fromCombo->addItems(names);
ui->toCombo->addItems(names);
ui->fromCombo->setCurrentIndex(category == Conversion::Category::Length ? 2 : 0);
ui->toCombo->setCurrentIndex(1);
clearResult();
}
void MainWindow::clearResult()
{
ui->resultEdit->clear();
ui->formulaLabel->setText(tr("选择单位并输入数值,点击“换算”查看计算过程。"));
ui->statusLabel->clear();
ui->copyButton->setEnabled(false);
}
void MainWindow::convertValue()
{
const auto category = ui->categoryCombo->currentIndex() == 0
? Conversion::Category::Temperature : Conversion::Category::Length;
const auto result = Conversion::convert(ui->inputEdit->text(), category,
ui->fromCombo->currentIndex(),
ui->toCombo->currentIndex());
if (!result.ok) {
clearResult();
ui->statusLabel->setText(result.error);
ui->inputEdit->setFocus();
return;
}
ui->resultEdit->setText(QStringLiteral("%1 %2")
.arg(result.value, 0, 'g', 12).arg(ui->toCombo->currentText()));
ui->formulaLabel->setText(result.explanation);
ui->statusLabel->setText(tr("换算完成。结果最多显示 12 位有效数字。"));
ui->copyButton->setEnabled(true);
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <QMainWindow>
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
private:
Ui::MainWindow *ui;
void changeCategory();
void clearResult();
void convertValue();
};
+246
View File
@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="windowTitle">
<string>单位换算器</string>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>840</width>
<height>650</height>
</rect>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="rootLayout">
<property name="spacing">
<number>12</number>
</property>
<property name="leftMargin">
<number>24</number>
</property>
<property name="topMargin">
<number>24</number>
</property>
<property name="rightMargin">
<number>24</number>
</property>
<property name="bottomMargin">
<number>24</number>
</property>
<item>
<widget class="QLabel" name="titleLabel">
<property name="text">
<string>单位换算器</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="subtitleLabel">
<property name="text">
<string>输入一个数值,查看换算结果和计算过程。</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="inputGroup">
<property name="title">
<string>输入与单位</string>
</property>
<layout class="QGridLayout" name="inputLayout" columnstretch="1,1">
<property name="spacing">
<number>12</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="categoryLabel">
<property name="text">
<string>换算类型</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="inputLabel">
<property name="text">
<string>输入数值</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="categoryCombo" />
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="inputEdit">
<property name="placeholderText">
<string>例如 25、-10.5 或 1e3</string>
</property>
<property name="maxLength">
<number>100</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="fromLabel">
<property name="text">
<string>源单位</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="toLabel">
<property name="text">
<string>目标单位</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QComboBox" name="fromCombo" />
</item>
<item row="3" column="1">
<widget class="QComboBox" name="toCombo" />
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="actionLayout">
<property name="spacing">
<number>12</number>
</property>
<item>
<widget class="QPushButton" name="convertButton">
<property name="text">
<string>换算</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="swapButton">
<property name="text">
<string>交换单位</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="text">
<string>清空输入</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="resultGroup">
<property name="title">
<string>换算结果</string>
</property>
<layout class="QVBoxLayout" name="resultLayout">
<property name="spacing">
<number>12</number>
</property>
<item>
<widget class="QLineEdit" name="resultEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>结果将在这里显示</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="formulaLabel">
<property name="text">
<string />
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>70</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copyButton">
<property name="text">
<string>复制结果</string>
</property>
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabel">
<property name="text">
<string />
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>55</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="helpLabel">
<property name="text">
<string>长度须为非负数,温度须不低于绝对零度。修改输入或单位后,需要重新换算。</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources />
<connections />
</ui>
@@ -0,0 +1,90 @@
#include <QtTest>
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>
#include <QPushButton>
#include "conversion.h"
#include "mainwindow.h"
#include <QApplication>
#include <QDir>
#include "appearance.h"
static void savePreview(QWidget &window, const QString &fileName)
{
const QString folder = QString::fromLocal8Bit(qgetenv("QT_TEACHING_SCREENSHOTS"));
if (folder.isEmpty()) return;
QDir().mkpath(folder);
window.show();
QApplication::processEvents();
QVERIFY(window.grab().save(QDir(folder).filePath(fileName)));
}
class ConverterTest : public QObject {
Q_OBJECT
private slots:
void initTestCase() { applyAppearance(*qApp); }
void knownValues_data()
{
QTest::addColumn<int>("category");
QTest::addColumn<QString>("input");
QTest::addColumn<int>("from");
QTest::addColumn<int>("to");
QTest::addColumn<double>("expected");
QTest::newRow("freezing") << 0 << QStringLiteral("0") << 0 << 1 << 32.0;
QTest::newRow("boiling") << 0 << QStringLiteral("212") << 1 << 0 << 100.0;
QTest::newRow("minus40") << 0 << QStringLiteral("-40") << 0 << 1 << -40.0;
QTest::newRow("kelvin") << 0 << QStringLiteral("273.15") << 2 << 0 << 0.0;
QTest::newRow("absolute-zero-C") << 0 << QStringLiteral("-273.15") << 0 << 2 << 0.0;
QTest::newRow("absolute-zero-F") << 0 << QStringLiteral("-459.67") << 1 << 2 << 0.0;
QTest::newRow("meter-cm") << 1 << QStringLiteral("1") << 2 << 1 << 100.0;
QTest::newRow("inch-cm") << 1 << QStringLiteral("1") << 4 << 1 << 2.54;
QTest::newRow("foot-meter") << 1 << QStringLiteral("1") << 5 << 2 << 0.3048;
QTest::newRow("km-mm") << 1 << QStringLiteral("1") << 3 << 0 << 1000000.0;
QTest::newRow("scientific") << 1 << QStringLiteral(" 1e3 ") << 0 << 2 << 1.0;
QTest::newRow("same-unit") << 1 << QStringLiteral("12.25") << 2 << 2 << 12.25;
}
void knownValues()
{
QFETCH(int, category); QFETCH(QString, input);
QFETCH(int, from); QFETCH(int, to); QFETCH(double, expected);
auto result = Conversion::convert(input, static_cast<Conversion::Category>(category), from, to);
QVERIFY2(result.ok, qPrintable(result.error));
QVERIFY(qAbs(result.value - expected) <= 1e-9 * qMax(1.0, qAbs(expected)));
}
void rejectsInvalid()
{
for (const QString &text : {QString(), QStringLiteral("12abc"), QStringLiteral("nan"),
QStringLiteral("inf"), QStringLiteral("1,000"), QStringLiteral("1e309")})
QVERIFY(!Conversion::convert(text, Conversion::Category::Length, 2, 1).ok);
QVERIFY(!Conversion::convert(QStringLiteral("-1"), Conversion::Category::Length, 2, 1).ok);
QVERIFY(!Conversion::convert(QStringLiteral("-274"), Conversion::Category::Temperature, 0, 2).ok);
QVERIFY(!Conversion::convert(QStringLiteral("-0.1"), Conversion::Category::Temperature, 2, 0).ok);
QVERIFY(!Conversion::convert(QStringLiteral("1e308"), Conversion::Category::Length, 3, 0).ok);
}
void uiWorkflow()
{
MainWindow w; w.show();
auto *input = w.findChild<QLineEdit *>(QStringLiteral("inputEdit"));
auto *result = w.findChild<QLineEdit *>(QStringLiteral("resultEdit"));
auto *convert = w.findChild<QPushButton *>(QStringLiteral("convertButton"));
input->setText(QStringLiteral("25"));
QTest::mouseClick(convert, Qt::LeftButton);
QVERIFY(result->text().startsWith(QStringLiteral("77 ")));
savePreview(w, QStringLiteral("01_converter.png"));
input->setText(QStringLiteral("bad"));
QVERIFY(result->text().isEmpty());
QTest::mouseClick(convert, Qt::LeftButton);
QVERIFY(!w.findChild<QLabel *>(QStringLiteral("statusLabel"))->text().isEmpty());
QVERIFY(!w.findChild<QPushButton *>(QStringLiteral("copyButton"))->isEnabled());
w.findChild<QComboBox *>(QStringLiteral("categoryCombo"))->setCurrentIndex(1);
input->setText(QStringLiteral("1"));
QTest::mouseClick(convert, Qt::LeftButton);
QVERIFY(result->text().startsWith(QStringLiteral("100 ")));
QTest::mouseClick(w.findChild<QPushButton *>(QStringLiteral("swapButton")), Qt::LeftButton);
QTest::mouseClick(convert, Qt::LeftButton);
QVERIFY(result->text().startsWith(QStringLiteral("0.01 ")));
}
};
QTEST_MAIN(ConverterTest)
#include "test_UnitConverter.moc"
@@ -0,0 +1,11 @@
QT += widgets testlib
CONFIG += c++14 console testcase
greaterThan(QT_MAJOR_VERSION, 5): CONFIG += c++17
TEMPLATE = app
TARGET = test_UnitConverter
INCLUDEPATH += ..
SOURCES += test_UnitConverter.cpp ../mainwindow.cpp ../conversion.cpp
HEADERS += ../mainwindow.h ../conversion.h
FORMS += ../mainwindow.ui
msvc: QMAKE_CXXFLAGS += /utf-8