Skip to content
This repository was archived by the owner on Mar 28, 2026. It is now read-only.

Commit 112c2a2

Browse files
committed
Add tests for base URL extraction
1 parent f7452af commit 112c2a2

File tree

5 files changed

+326
-0
lines changed

5 files changed

+326
-0
lines changed

.github/workflows/test.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: test
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Install dependencies
16+
run: |
17+
sudo apt-get update
18+
sudo apt-get install --yes \
19+
build-essential \
20+
cmake \
21+
ninja-build \
22+
qtbase5-dev \
23+
qtwebengine5-dev \
24+
qtdeclarative5-dev \
25+
libqt5x11extras5-dev \
26+
libmpv-dev \
27+
libcec-dev \
28+
lirc \
29+
libminizip-dev \
30+
libsdl2-dev
31+
32+
- name: Configure
33+
run: cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug
34+
35+
- name: Build
36+
run: cmake --build build
37+
38+
- name: Run tests
39+
run: |
40+
cd build
41+
ctest --output-on-failure

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ endif(Qt5_POSITION_INDEPENDENT_CODE)
7777
add_subdirectory(external)
7878
add_subdirectory(src)
7979

80+
enable_testing()
81+
add_subdirectory(tests)
82+
8083
include(CPackConfiguration)
8184

8285
add_custom_target(install_app_bundle COMMAND ${CMAKE_COMMAND} -P cmake_install.cmake DEPENDS JellyfinMediaPlayer)

CONTRIBUTING.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Contributing to Jellyfin Media Player
2+
3+
## Running Tests
4+
5+
Jellyfin Media Player uses Qt Test for unit testing.
6+
7+
### Building Tests
8+
9+
Tests are built automatically when you build the project:
10+
11+
```sh
12+
cmake -B build
13+
cmake --build build
14+
```
15+
16+
### Running Tests
17+
18+
Run all tests using CTest:
19+
20+
```sh
21+
cd build
22+
ctest
23+
```
24+
25+
Or run individual test executables directly:
26+
27+
```sh
28+
cd build
29+
./tests/test_systemcomponent
30+
```
31+
32+
### Writing Tests
33+
34+
Tests are located in the `tests/` directory. To add a new test:
35+
36+
1. Create a test file in `tests/` (e.g., `test_mycomponent.cpp`)
37+
2. Use `QTEST_APPLESS_MAIN` for headless unit tests
38+
3. Add the test to `tests/CMakeLists.txt`
39+
40+
Example test structure:
41+
42+
```cpp
43+
#include <QtTest/QtTest>
44+
#include "../src/mycomponent/MyComponent.h"
45+
46+
class TestMyComponent : public QObject
47+
{
48+
Q_OBJECT
49+
50+
private slots:
51+
void testMyFunction_data();
52+
void testMyFunction();
53+
};
54+
55+
void TestMyComponent::testMyFunction_data()
56+
{
57+
QTest::addColumn<QString>("input");
58+
QTest::addColumn<QString>("expected");
59+
60+
QTest::newRow("test case 1") << "input1" << "output1";
61+
QTest::newRow("test case 2") << "input2" << "output2";
62+
}
63+
64+
void TestMyComponent::testMyFunction()
65+
{
66+
QFETCH(QString, input);
67+
QFETCH(QString, expected);
68+
69+
QString result = MyComponent::myFunction(input);
70+
QCOMPARE(result, expected);
71+
}
72+
73+
QTEST_APPLESS_MAIN(TestMyComponent)
74+
#include "test_mycomponent.moc"
75+
```
76+
77+
For more information on Qt Test, see the [Qt Test documentation](https://doc.qt.io/qt-6/qtest-overview.html).

tests/CMakeLists.txt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
cmake_minimum_required(VERSION 3.5.0)
2+
3+
set(CMAKE_AUTOMOC ON)
4+
5+
# Find Qt5 Test module
6+
find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Test Core Network)
7+
8+
# Get all source files that are part of the main application
9+
get_property(ALL_SRCS GLOBAL PROPERTY SRCS_LIST)
10+
11+
# Create test executable - link against all application sources
12+
add_executable(test_systemcomponent
13+
test_systemcomponent.cpp
14+
${ALL_SRCS}
15+
)
16+
17+
# Link Qt5 libraries and other dependencies
18+
target_link_libraries(test_systemcomponent
19+
shared
20+
Qt5::Test
21+
Qt5::Core
22+
Qt5::Network
23+
${QT5_LIBRARIES}
24+
${MPV_LIBRARY}
25+
${OPENGL_LIBS}
26+
${OS_LIBS}
27+
${EXTRA_LIBS}
28+
${X11_LIBRARIES}
29+
${X11_Xrandr_LIB}
30+
${ICU_LIBRARIES}
31+
${CMAKE_THREAD_LIBS_INIT}
32+
${RPI_LIBS}
33+
${MINIZIP_LIBS}
34+
)
35+
36+
# Include directories - match main application
37+
target_include_directories(test_systemcomponent PRIVATE
38+
${CMAKE_SOURCE_DIR}/src
39+
${CMAKE_SOURCE_DIR}/src/core
40+
${CMAKE_SOURCE_DIR}/src/shared
41+
${CMAKE_SOURCE_DIR}/external
42+
${CMAKE_SOURCE_DIR}/external/HIDRemote
43+
${CMAKE_SOURCE_DIR}/external/plistparser
44+
${CMAKE_SOURCE_DIR}/external/letsmove
45+
${CMAKE_SOURCE_DIR}/src/player
46+
)
47+
48+
# Add compile definitions
49+
target_compile_definitions(test_systemcomponent PRIVATE
50+
PREFIX="${CMAKE_INSTALL_PREFIX}"
51+
)
52+
53+
# Add test to CTest
54+
add_test(NAME test_systemcomponent COMMAND test_systemcomponent)

tests/test_systemcomponent.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include <QtTest/QtTest>
2+
#include "../src/system/SystemComponent.h"
3+
4+
class TestSystemComponent : public QObject
5+
{
6+
Q_OBJECT
7+
8+
private slots:
9+
void testExtractBaseUrl_data();
10+
void testExtractBaseUrl();
11+
};
12+
13+
void TestSystemComponent::testExtractBaseUrl_data()
14+
{
15+
QTest::addColumn<QString>("input");
16+
QTest::addColumn<QString>("expected");
17+
18+
// Standard cases - URLs with /web
19+
QTest::newRow("https with /web at root")
20+
<< "https://server.com/web/"
21+
<< "https://server.com";
22+
23+
QTest::newRow("https with /web and custom port")
24+
<< "https://server.com:8096/web/"
25+
<< "https://server.com:8096";
26+
27+
QTest::newRow("http with /web and port 80")
28+
<< "http://server.com:80/web/"
29+
<< "http://server.com";
30+
31+
QTest::newRow("https with /web and port 443")
32+
<< "https://server.com:443/web/"
33+
<< "https://server.com";
34+
35+
QTest::newRow("https with /web at subpath")
36+
<< "https://server.com/jellyfin/web/"
37+
<< "https://server.com/jellyfin";
38+
39+
QTest::newRow("https with /web, no trailing slash")
40+
<< "https://server.com/jellyfin/web"
41+
<< "https://server.com/jellyfin";
42+
43+
QTest::newRow("https with nested path before /web")
44+
<< "https://server.com/path/to/jellyfin/web/"
45+
<< "https://server.com/path/to/jellyfin";
46+
47+
// Case insensitivity
48+
QTest::newRow("https with /WEB uppercase")
49+
<< "https://server.com/WEB/"
50+
<< "https://server.com";
51+
52+
QTest::newRow("https with /Web mixed case")
53+
<< "https://server.com/jellyfin/Web/"
54+
<< "https://server.com/jellyfin";
55+
56+
// Fallback cases - URLs without /web
57+
QTest::newRow("https root without /web")
58+
<< "https://server.com/"
59+
<< "https://server.com";
60+
61+
QTest::newRow("https with port, no /web")
62+
<< "https://server.com:8096/"
63+
<< "https://server.com:8096";
64+
65+
QTest::newRow("http with port 80, no /web")
66+
<< "http://server.com:80/"
67+
<< "http://server.com";
68+
69+
QTest::newRow("https with port 443, no /web")
70+
<< "https://server.com:443/"
71+
<< "https://server.com";
72+
73+
QTest::newRow("https with path but no /web")
74+
<< "https://server.com/some/path"
75+
<< "https://server.com";
76+
77+
QTest::newRow("http root without /web")
78+
<< "http://server.com"
79+
<< "http://server.com";
80+
81+
// Edge cases - query strings and fragments
82+
QTest::newRow("https with /web and query string")
83+
<< "https://server.com/web/?foo=bar"
84+
<< "https://server.com";
85+
86+
QTest::newRow("https with /web and fragment")
87+
<< "https://server.com/web/#section"
88+
<< "https://server.com";
89+
90+
QTest::newRow("https with /web, query and fragment")
91+
<< "https://server.com/jellyfin/web/?foo=bar#section"
92+
<< "https://server.com/jellyfin";
93+
94+
// Edge cases - partial matches
95+
QTest::newRow("https with /website (not /web)")
96+
<< "https://server.com/website/"
97+
<< "https://server.com";
98+
99+
QTest::newRow("https with /webdav (not /web)")
100+
<< "https://server.com/webdav/"
101+
<< "https://server.com";
102+
103+
// Edge cases - multiple /web occurrences (should use last)
104+
QTest::newRow("https with multiple /web - uses last")
105+
<< "https://server.com/web/something/web/"
106+
<< "https://server.com/web/something";
107+
108+
// Edge cases - localhost and IP addresses
109+
QTest::newRow("localhost with port")
110+
<< "http://localhost:8096/web/"
111+
<< "http://localhost:8096";
112+
113+
QTest::newRow("IPv4 address")
114+
<< "http://192.168.1.100:8096/web/"
115+
<< "http://192.168.1.100:8096";
116+
117+
QTest::newRow("IPv6 address")
118+
<< "http://[::1]:8096/web/"
119+
<< "http://::1:8096";
120+
121+
// Edge cases - malformed/empty
122+
QTest::newRow("empty string")
123+
<< ""
124+
<< "://";
125+
126+
QTest::newRow("no scheme")
127+
<< "server.com/web/"
128+
<< "://server.com";
129+
130+
QTest::newRow("only scheme")
131+
<< "https://"
132+
<< "https://";
133+
134+
QTest::newRow("no host")
135+
<< "https:///web/"
136+
<< "https://";
137+
}
138+
139+
void TestSystemComponent::testExtractBaseUrl()
140+
{
141+
QFETCH(QString, input);
142+
QFETCH(QString, expected);
143+
144+
SystemComponent* component = &SystemComponent::Get();
145+
QString result = component->extractBaseUrl(input);
146+
147+
QCOMPARE(result, expected);
148+
}
149+
150+
QTEST_APPLESS_MAIN(TestSystemComponent)
151+
#include "test_systemcomponent.moc"

0 commit comments

Comments
 (0)