Skip to content

Commit

Permalink
Add some basic tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 25, 2024
1 parent 4aae643 commit b7edafd
Show file tree
Hide file tree
Showing 11 changed files with 812 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
cd build
cmake -GNinja \
-Do2_BUILD_EXAMPLES:BOOL=ON \
-Do2_WITH_TESTS=ON \
-Do2_SHOW_TRACE:BOOL=ON \
-Do2_WITH_DROPBOX:BOOL=ON \
-Do2_WITH_FACEBOOK:BOOL=ON \
Expand All @@ -51,3 +52,8 @@ jobs:
..
ninja
- name: Run Tests
run: |
cd build
ctest --output-on-failure --no-compress-output -T Test
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ if(NOT o2_SHOW_TRACE)
add_definitions(-DQT_NO_DEBUG_OUTPUT=1)
endif()

option(o2_WITH_TESTS "Enable tests" OFF)
option(o2_WITH_TWITTER "Authenticate with Twitter" OFF)
option(o2_WITH_DROPBOX "Authenticate with Dropbox" OFF)
option(o2_WITH_GOOGLE "Authenticate with Google" OFF)
Expand Down Expand Up @@ -104,3 +105,8 @@ add_subdirectory(src)
if(o2_BUILD_EXAMPLES)
add_subdirectory(examples)
endif(o2_BUILD_EXAMPLES)

if(o2_WITH_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
3 changes: 3 additions & 0 deletions src/o0baseauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ public Q_SLOTS:
private:
O2ReplyServer *replyServer_{nullptr};
O2PollServer *pollServer_{nullptr};

friend class TestBaseAuth;
friend class TestO2;
};

#endif // O0BASEAUTH
2 changes: 2 additions & 0 deletions src/o2.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ protected Q_SLOTS:
O2ReplyList timedReplies_;
GrantFlow grantFlow_;
QString grantType_;

friend class TestO2;
};

#endif // O2_H
103 changes: 103 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# CMakeLists.txt for ./tests directory
cmake_minimum_required(VERSION 3.1.0)

# Test configuration
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

# Find Qt packages needed for testing
if(o2_WITH_QT5)
find_package(Qt5 5.15 COMPONENTS Core Network Test REQUIRED)
else()
find_package(Qt6 COMPONENTS Core Network Test REQUIRED)
endif()

# Source files from src directory
set(SOURCE_FILES
${CMAKE_SOURCE_DIR}/src/o0baseauth.cpp
${CMAKE_SOURCE_DIR}/src/o0jsonresponse.cpp
${CMAKE_SOURCE_DIR}/src/o2.cpp
${CMAKE_SOURCE_DIR}/src/o2pollserver.cpp
${CMAKE_SOURCE_DIR}/src/o2reply.cpp
${CMAKE_SOURCE_DIR}/src/o2replyserver.cpp
${CMAKE_SOURCE_DIR}/src/o2requestor.cpp
${CMAKE_SOURCE_DIR}/src/o0settingsstore.cpp
${CMAKE_SOURCE_DIR}/src/o2simplecrypt.cpp
)

# Header files from src directory
set(HEADER_FILES
${CMAKE_SOURCE_DIR}/src/o0abstractstore.h
${CMAKE_SOURCE_DIR}/src/o0baseauth.h
${CMAKE_SOURCE_DIR}/src/o2.h
${CMAKE_SOURCE_DIR}/src/o2pollserver.h
${CMAKE_SOURCE_DIR}/src/o2reply.h
${CMAKE_SOURCE_DIR}/src/o2replyserver.h
${CMAKE_SOURCE_DIR}/src/o2requestor.h
${CMAKE_SOURCE_DIR}/src/o0settingsstore.h
${CMAKE_SOURCE_DIR}/src/o0export.h
${CMAKE_SOURCE_DIR}/src/o0globals.h
${CMAKE_SOURCE_DIR}/src/o0jsonresponse.h
)

# Test utilities header
set(TEST_UTILS
testutils.h
)

# Test files in current directory
set(TEST_FILES
testbaseauth.cpp
teststore.cpp
testreplyserver.cpp
testcrypt.cpp
testo2.cpp
)

# Enable testing
enable_testing()

# Function to create test executable
function(add_oauth_test TEST_FILE)
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
add_executable(${TEST_NAME}
${TEST_FILE}
${TEST_UTILS}
${SOURCE_FILES}
${HEADER_FILES}
)

target_link_libraries(${TEST_NAME}
PRIVATE
Qt::Core
Qt::Network
Qt::Test
)

target_include_directories(${TEST_NAME}
PRIVATE
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}
)

add_test(NAME ${TEST_NAME}
COMMAND ${TEST_NAME}
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

set_target_properties(${TEST_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
endfunction()

# Create test executables
foreach(TEST_FILE ${TEST_FILES})
add_oauth_test(${TEST_FILE})
endforeach()

# Add custom target to run all tests
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
102 changes: 102 additions & 0 deletions tests/testbaseauth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <QtTest>
#include "o0baseauth.h"
#include "o0globals.h"
#include "testutils.h"

// Concrete implementation of O0BaseAuth for testing
class TestableAuth : public O0BaseAuth {
Q_OBJECT
public:
explicit TestableAuth(QObject *parent = nullptr, O0AbstractStore *store = nullptr)
: O0BaseAuth(parent, store) {}

// Implement pure virtual functions
void link() override {
}

void unlink() override {
}
};

class TestBaseAuth : public QObject {
Q_OBJECT

private slots:
void initTestCase() {
store = new MockStore(this);
auth = new TestableAuth(this, store);
}

void cleanupTestCase() {
delete auth; // store will be deleted by parent-child relationship
}

void init() {
}

void testClientConfiguration() {
QString testClientId = "testClient";
QString testClientSecret = "testSecret";

auth->setClientId(testClientId);
auth->setClientSecret(testClientSecret);

QCOMPARE(auth->clientId(), testClientId);
QCOMPARE(auth->clientSecret(), testClientSecret);
}

void testLinkedState() {
QVERIFY(!auth->linked());
auth->setLinked(true);
QVERIFY(auth->linked());

// Verify the actual stored value
QString key = QString(O2_KEY_LINKED).arg(auth->clientId());
QCOMPARE(store->values[key], QString("1"));
}

void testTokenManagement() {
QString testToken = "testToken";
auth->setToken(testToken);
QCOMPARE(auth->token(), testToken);

// Verify the actual stored value
QString tokenKey = QString(O2_KEY_TOKEN).arg(auth->clientId());
QCOMPARE(store->values[tokenKey], testToken);
}

void testTokenSecretManagement() {
QString testSecret = "testSecret";
auth->setTokenSecret(testSecret);
QCOMPARE(auth->tokenSecret(), testSecret);

// Verify the actual stored value
QString secretKey = QString(O2_KEY_TOKEN_SECRET).arg(auth->clientId());
QCOMPARE(store->values[secretKey], testSecret);
}

void testExtraTokens() {
QVariantMap tokens;
tokens["extra1"] = "value1";
tokens["extra2"] = "value2";

auth->setExtraTokens(tokens);
QVariantMap retrievedTokens = auth->extraTokens();

QCOMPARE(retrievedTokens["extra1"].toString(), QString("value1"));
QCOMPARE(retrievedTokens["extra2"].toString(), QString("value2"));
}

void testLocalPort() {
int testPort = 8080;
auth->setLocalPort(testPort);
QCOMPARE(auth->localPort(), testPort);
}

private:
MockStore* store;
TestableAuth* auth; // Changed to TestableAuth
};

QTEST_MAIN(TestBaseAuth)
#include "testbaseauth.moc"
63 changes: 63 additions & 0 deletions tests/testcrypt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <QtTest>
#include "o0simplecrypt.h"

class TestSimpleCrypt : public QObject {
Q_OBJECT

private slots:
void initTestCase() {
crypt = new O0SimpleCrypt(Q_UINT64_C(0x0c2ad4a4acb9f023));
}

void cleanupTestCase() {
delete crypt;
}

void testStringEncryption() {
QString original = "Test string for encryption";
QString encrypted = crypt->encryptToString(original);
QString decrypted = crypt->decryptToString(encrypted);

QVERIFY(encrypted != original);
QCOMPARE(decrypted, original);
}

void testCompressionModes_data() {
QTest::addColumn<int>("compressionMode");
QTest::addColumn<QString>("testData");

QTest::newRow("always") << static_cast<int>(O0SimpleCrypt::CompressionAlways)
<< QString("A").repeated(1000);
QTest::newRow("never") << static_cast<int>(O0SimpleCrypt::CompressionNever)
<< QString("A").repeated(1000);
}

void testCompressionModes() {
QFETCH(int, compressionMode);
QFETCH(QString, testData);

crypt->setCompressionMode(static_cast<O0SimpleCrypt::CompressionMode>(compressionMode));
QString encrypted = crypt->encryptToString(testData);
QString decrypted = crypt->decryptToString(encrypted);
QCOMPARE(decrypted, testData);
}

void testIntegrityProtection() {
QString testData = "Test data for integrity check";

crypt->setIntegrityProtectionMode(O0SimpleCrypt::ProtectionChecksum);
QString encrypted = crypt->encryptToString(testData);

// Test tampering detection
QString tampered = encrypted;
tampered[tampered.length()/2] = QChar( tampered[tampered.length()/2].toLatin1() + 1 );
QVERIFY(crypt->decryptToString(tampered).isEmpty());
QCOMPARE(crypt->lastError(), O0SimpleCrypt::ErrorIntegrityFailed);
}

private:
O0SimpleCrypt* crypt;
};

QTEST_MAIN(TestSimpleCrypt)
#include "testcrypt.moc"
Loading

0 comments on commit b7edafd

Please sign in to comment.