Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build and Test

on:
push:
branches: [ "**" ]
pull_request:
branches: [ "**" ]

jobs:
linux:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
ninja-build \
pkg-config \
libevent-dev \
libsqlite3-dev \
zlib1g-dev \
libboost-all-dev \
qt6-base-dev \
qt6-declarative-dev \
libqt6quickcontrols2-dev

- name: Configure (CMake)
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_APP_TESTS=ON

- name: Build
run: cmake --build build --parallel

- name: Run tests
run: ctest --test-dir build --output-on-failure

9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,11 @@ target_link_libraries(bitcoin-core-app
bitcoin_node
bitcoinqml
bitcoinqt
)
)

option(BUILD_APP_TESTS "Build unit tests for the app" ON)
if(BUILD_APP_TESTS)
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@ appropriate document for your platform:

- [build-unix.md](https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md)

In addition the following dependencies are required for the GUI:
In addition the following dependencies are required for the GUI and tests:

#### Debian-based systems:

```
sudo apt install \
qt6-base-dev \
qt6-base-dev-tools \
qt6-tools-dev \
qt6-l10n-tools \
qt6-tools-dev-tools \
Expand All @@ -91,6 +92,8 @@ sudo apt install qt6-wayland

```
brew install qt@6 qrencode
# Help CMake find Qt6 on macOS (adjust if needed)
export CMAKE_PREFIX_PATH="$(brew --prefix qt@6)/lib/cmake"
```

### Build
Expand All @@ -116,5 +119,20 @@ Binaries are exported to the `build/` directory:
build/bin/bitcoin-core-app
```

### Run Tests

- Enable tests at configure time and run them via CTest.

```
cmake -B build -DBUILD_APP_TESTS=ON
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure
```

- If CMake reports "Target Qt6::Test not found", ensure Qt6 Test is available
and discoverable by CMake:

- Debian/Ubuntu: `qt6-base-dev` provides the Qt Test module (already listed above).
- macOS: set `CMAKE_PREFIX_PATH` as shown so CMake can locate Qt 6 modules.


25 changes: 25 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.22)

# Tests for the QML/Qt6 app

find_package(Qt 6.2 MODULE REQUIRED COMPONENTS Test Core)

add_executable(bitcoinqml_tests
test_bitcoinamount.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../qml/bitcoinamount.cpp
)

target_include_directories(bitcoinqml_tests
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../bitcoin/src
)

target_link_libraries(bitcoinqml_tests
PRIVATE
Qt6::Core
Qt6::Test
)

add_test(NAME bitcoinqml_tests COMMAND bitcoinqml_tests)

78 changes: 78 additions & 0 deletions test/test_bitcoinamount.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) 2025 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <QtTest/QtTest>

#include <qml/bitcoinamount.h>

class BitcoinAmountTests : public QObject {
Q_OBJECT

private Q_SLOTS:
void satsToBtcString_basic();
void satsToBtcString_negative();
void btcToSats_roundtrip();
void sanitize_clampsAndFilters();
void display_flow_btc();
void display_flow_sat();
void flipUnit_changesLabelAndDisplaySignal();
};

void BitcoinAmountTests::satsToBtcString_basic()
{
QCOMPARE(BitcoinAmount::satsToBtcString(0), QString("0.00000000"));
QCOMPARE(BitcoinAmount::satsToBtcString(1), QString("0.00000001"));
QCOMPARE(BitcoinAmount::satsToBtcString(COIN), QString("1.00000000"));
QCOMPARE(BitcoinAmount::satsToBtcString(21 * COIN), QString("21.00000000"));
QCOMPARE(BitcoinAmount::satsToBtcString(100000123), QString("1.00000123"));
}

void BitcoinAmountTests::satsToBtcString_negative()
{
QCOMPARE(BitcoinAmount::satsToBtcString(-1), QString("-0.00000001"));
}

void BitcoinAmountTests::btcToSats_roundtrip()
{
BitcoinAmount amt;
amt.setUnit(BitcoinAmount::Unit::BTC);
amt.fromDisplay("1.23456789");
QCOMPARE(amt.toDisplay(), QString("1.23456789"));
}

void BitcoinAmountTests::sanitize_clampsAndFilters()
{
BitcoinAmount amt;
amt.setUnit(BitcoinAmount::Unit::BTC);
amt.fromDisplay("abc1.2.3xyz");
QCOMPARE(amt.toDisplay(), QString("1.20000000"));
}

void BitcoinAmountTests::display_flow_btc()
{
BitcoinAmount amt;
amt.setUnit(BitcoinAmount::Unit::BTC);
amt.setSatoshi(2 * COIN);
QCOMPARE(amt.toDisplay(), QString("2.00000000"));
}

void BitcoinAmountTests::display_flow_sat()
{
BitcoinAmount amt;
amt.setUnit(BitcoinAmount::Unit::SAT);
amt.setSatoshi(123);
QCOMPARE(amt.toDisplay(), QString("123"));
}

void BitcoinAmountTests::flipUnit_changesLabelAndDisplaySignal()
{
BitcoinAmount amt;
amt.setSatoshi(100);
QSignalSpy spy(&amt, &BitcoinAmount::displayChanged);
amt.flipUnit();
QVERIFY(spy.count() >= 1);
}

QTEST_MAIN(BitcoinAmountTests)
#include "test_bitcoinamount.moc"
Loading