diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 68e4e0e..33ced78 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -2,9 +2,9 @@ name: Linux on: push: - branches: [ main ] + branches: [ main, 'game/*' ] pull_request: - branches: [ main ] + branches: [ main, 'game/*' ] jobs: build-and-test: diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index c925fe4..e1da849 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -2,9 +2,9 @@ name: macOS on: push: - branches: [ main ] + branches: [ main, 'game/*' ] pull_request: - branches: [ main ] + branches: [ main, 'game/*' ] jobs: build-and-test: diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 4145477..317d0f7 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -2,9 +2,9 @@ name: Windows on: push: - branches: [ main ] + branches: [ main, 'game/*' ] pull_request: - branches: [ main ] + branches: [ main, 'game/*' ] jobs: build-and-test: diff --git a/include/datacoe/game_data.hpp b/include/datacoe/game_data.hpp index 90e5147..b7364cf 100644 --- a/include/datacoe/game_data.hpp +++ b/include/datacoe/game_data.hpp @@ -11,16 +11,16 @@ namespace datacoe class GameData { std::string m_nickname; - std::array m_highscores; + std::array m_highscores; public: - GameData(const std::string& nickname = "", const std::array& highscores = {0}); + GameData(const std::string &nickname = "", const std::array &highscores = {0}); void setNickname(const std::string& nickname); - void setHighscores(const std::array& highscores); + void setHighscores(const std::array &highscores); const std::string& getNickname() const; - const std::array& getHighscores() const; + const std::array &getHighscores() const; json toJson() const; diff --git a/src/game_data.cpp b/src/game_data.cpp index fa14276..7081214 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp @@ -3,15 +3,15 @@ namespace datacoe { - GameData::GameData(const std::string &nickname, const std::array& highscores) : m_nickname(nickname), m_highscores(highscores) {} + GameData::GameData(const std::string &nickname, const std::array &highscores) : m_nickname(nickname), m_highscores(highscores) {} void GameData::setNickname(const std::string &nickname) { m_nickname = nickname; } - void GameData::setHighscores(const std::array &highscores) { m_highscores = highscores; } + void GameData::setHighscores(const std::array &highscores) { m_highscores = highscores; } const std::string &GameData::getNickname() const { return m_nickname; } - const std::array &GameData::getHighscores() const { return m_highscores; } + const std::array &GameData::getHighscores() const { return m_highscores; } json GameData::toJson() const { @@ -24,7 +24,7 @@ namespace datacoe GameData GameData::fromJson(const json &j) { std::string nickname; - std::array highscores; + std::array highscores; if (j.contains("nickname") && j["nickname"].is_string()) { try { nickname = j["nickname"].get(); } @@ -35,7 +35,7 @@ namespace datacoe if (j.contains("highscores") && j["highscores"].is_array() && j["highscores"].size() == 4) { - try { highscores = j["highscore"].get>(); } + try { highscores = j["highscores"].get>(); } catch (const json::exception &) { throw; } } else diff --git a/tests/data_manager_tests.cpp b/tests/data_manager_tests.cpp index e3e5803..0ea1d7e 100644 --- a/tests/data_manager_tests.cpp +++ b/tests/data_manager_tests.cpp @@ -1,7 +1,8 @@ -#include +#include "gtest/gtest.h" #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ namespace datacoe std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Try to clean up the test file - for (int i = 0; i < 5; i++) + for (std::size_t i = 0; i < 5; i++) { try { @@ -59,28 +60,28 @@ namespace datacoe { try { + // Create GameData and set in DataManager DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - // Create a GameData object and set it in the DataManager - GameData gameData; - gameData.setNickname("TestUser"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + // Create and set GameData + GameData data; + data.setNickname("TestUser"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); ASSERT_TRUE(dm.saveGame()) << "Failed to save game"; ASSERT_TRUE(std::filesystem::exists(m_testFilename)) << "Save file not created"; // Create a new DataManager to load the saved data DataManager dm2; - bool loadResult = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file"; + dm2.init(m_testFilename); const GameData &loadedData = dm2.getGamedata(); ASSERT_EQ(loadedData.getNickname(), "TestUser"); - ASSERT_EQ(loadedData.getHighscore(), 100); + ASSERT_EQ(loadedData.getHighscores(), scores); } catch (const std::exception &e) { @@ -93,32 +94,32 @@ namespace datacoe try { DataManager dm; - bool initialInit = dm.init(m_testFilename); - ASSERT_FALSE(initialInit) << "init() should return false for new file"; + dm.init(m_testFilename); // Set initial data and save - GameData gameData; - gameData.setNickname("TestUser"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + GameData data; + data.setNickname("TestUser"); + std::array initialScores = {100, 200, 300, 400}; + data.setHighscores(initialScores); + dm.setGamedata(data); ASSERT_TRUE(dm.saveGame()); - // Update high score and save again - GameData updatedData = dm.getGamedata(); // Get the current data - updatedData.setHighscore(200); // Update the score - dm.setGamedata(updatedData); // Set the updated data + // Update high scores and save again + GameData updatedData = dm.getGamedata(); + std::array updatedScores = {500, 600, 700, 800}; + updatedData.setHighscores(updatedScores); + dm.setGamedata(updatedData); ASSERT_TRUE(dm.saveGame()); // Load in a new manager DataManager dm2; - bool loadResult = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file"; + dm2.init(m_testFilename); const GameData &loadedData = dm2.getGamedata(); - // Check the updated score was saved + // Check the updated scores were saved ASSERT_EQ(loadedData.getNickname(), "TestUser"); - ASSERT_EQ(loadedData.getHighscore(), 200); + ASSERT_EQ(loadedData.getHighscores(), updatedScores); } catch (const std::exception &e) { @@ -131,14 +132,14 @@ namespace datacoe try { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; - - // Create initial data - GameData gameData; - gameData.setNickname("TestUser"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + dm.init(m_testFilename); + + // Set initial data + GameData data; + data.setNickname("TestUser"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); dm.saveGame(); // Create a new game @@ -148,16 +149,16 @@ namespace datacoe // Check reset to default values ASSERT_EQ(newData.getNickname(), ""); - ASSERT_EQ(newData.getHighscore(), 0); + std::array expectedScores = {0, 0, 0, 0}; + ASSERT_EQ(newData.getHighscores(), expectedScores); // Check that original saved data still exists on disk DataManager dm2; - bool loadResult = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file"; + dm2.init(m_testFilename); const GameData &loadedData = dm2.getGamedata(); ASSERT_EQ(loadedData.getNickname(), "TestUser"); - ASSERT_EQ(loadedData.getHighscore(), 100); + ASSERT_EQ(loadedData.getHighscores(), scores); } catch (const std::exception &e) { @@ -170,15 +171,13 @@ namespace datacoe try { DataManager dm; - bool initResult = dm.init("non_existent_file.json"); // Test loading a non-existent file - - // Should return false for non-existent file - ASSERT_FALSE(initResult) << "init() should return false for non-existent file"; + dm.init("non_existent_file.json"); // Test loading a non-existent file // Should initialize with default empty values const GameData &newData = dm.getGamedata(); ASSERT_EQ(newData.getNickname(), ""); - ASSERT_EQ(newData.getHighscore(), 0); + std::array expectedScores = {0, 0, 0, 0}; + ASSERT_EQ(newData.getHighscores(), expectedScores); } catch (const std::exception &e) { @@ -191,14 +190,14 @@ namespace datacoe try { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - // Empty nickname represents guest mode - GameData gameData; - gameData.setNickname(""); // Empty nickname for guest mode - gameData.setHighscore(500); - dm.setGamedata(gameData); + // Set empty nickname for guest mode + GameData data; + data.setNickname(""); // Empty nickname represents guest mode + std::array scores = {500, 600, 700, 800}; + data.setHighscores(scores); + dm.setGamedata(data); // Should return true but not create a file ASSERT_TRUE(dm.saveGame()); @@ -210,44 +209,44 @@ namespace datacoe } } - TEST_F(DataManagerTest, HighScoreUpdating) + TEST_F(DataManagerTest, HighscoreUpdating) { try { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); // Set initial data - GameData gameData; - gameData.setNickname("Player1"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + GameData initialData; + initialData.setNickname("Player1"); + std::array initialScores = {100, 200, 300, 400}; + initialData.setHighscores(initialScores); + dm.setGamedata(initialData); dm.saveGame(); - // Set a lower score - GameData updatedData = dm.getGamedata(); - updatedData.setHighscore(50); - dm.setGamedata(updatedData); + // Set lower scores + GameData lowerData = dm.getGamedata(); + std::array lowerScores = {50, 150, 250, 350}; + lowerData.setHighscores(lowerScores); + dm.setGamedata(lowerData); dm.saveGame(); - // Load data and verify the lower score was saved + // Load data and verify the lower scores were saved DataManager dm2; - bool loadResult1 = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult1) << "init() should return true when loading existing file"; - ASSERT_EQ(dm2.getGamedata().getHighscore(), 50); - - // Set a higher score - GameData newData = dm2.getGamedata(); - newData.setHighscore(200); - dm2.setGamedata(newData); + dm2.init(m_testFilename); + ASSERT_EQ(dm2.getGamedata().getHighscores(), lowerScores); + + // Set higher scores + GameData higherData = dm2.getGamedata(); + std::array higherScores = {200, 300, 400, 500}; + higherData.setHighscores(higherScores); + dm2.setGamedata(higherData); dm2.saveGame(); // Load again and verify DataManager dm3; - bool loadResult2 = dm3.init(m_testFilename); - ASSERT_TRUE(loadResult2) << "init() should return true when loading existing file"; - ASSERT_EQ(dm3.getGamedata().getHighscore(), 200); + dm3.init(m_testFilename); + ASSERT_EQ(dm3.getGamedata().getHighscores(), higherScores); } catch (const std::exception &e) { @@ -262,13 +261,14 @@ namespace datacoe // Create an unencrypted save file { DataManager dm; - bool initResult = dm.init(m_testFilename, false); // Unencrypted - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename, false); // Unencrypted + + GameData data; + data.setNickname("TransitionTest"); + std::array scores = {1000, 2000, 3000, 4000}; + data.setHighscores(scores); + dm.setGamedata(data); - GameData gameData; - gameData.setNickname("TransitionTest"); - gameData.setHighscore(1000); - dm.setGamedata(gameData); ASSERT_TRUE(dm.saveGame()) << "Failed to save unencrypted game"; // Verify it's unencrypted @@ -278,17 +278,18 @@ namespace datacoe // Load the file with encryption turned on { DataManager dm; - bool loadResult = dm.init(m_testFilename, true); // Encrypted mode - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file"; + dm.init(m_testFilename, true); // Encrypted mode // Should still load successfully due to auto-detection const GameData &data = dm.getGamedata(); ASSERT_EQ(data.getNickname(), "TransitionTest"); - ASSERT_EQ(data.getHighscore(), 1000); + std::array expectedScores = {1000, 2000, 3000, 4000}; + ASSERT_EQ(data.getHighscores(), expectedScores); // Modify data - GameData updatedData = dm.getGamedata(); - updatedData.setHighscore(2000); + GameData updatedData = data; + std::array updatedScores = {2000, 3000, 4000, 5000}; + updatedData.setHighscores(updatedScores); dm.setGamedata(updatedData); // Save with encryption turned on @@ -301,13 +302,13 @@ namespace datacoe // Load the now-encrypted file with encryption turned off { DataManager dm; - bool loadResult = dm.init(m_testFilename, false); // Unencrypted mode - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file (with auto-detection)"; + dm.init(m_testFilename, false); // Unencrypted mode // Should still load successfully due to auto-detection const GameData &data = dm.getGamedata(); ASSERT_EQ(data.getNickname(), "TransitionTest"); - ASSERT_EQ(data.getHighscore(), 2000); + std::array expectedScores = {2000, 3000, 4000, 5000}; + ASSERT_EQ(data.getHighscores(), expectedScores); } } catch (const std::exception &e) @@ -324,10 +325,13 @@ namespace datacoe { DataManager dm; dm.init(m_testFilename, false); // Unencrypted - GameData gameData; - gameData.setNickname("EncryptionChangeTest"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + + GameData data; + data.setNickname("EncryptionChangeTest"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()) << "Failed to save unencrypted game"; // Verify it's unencrypted @@ -338,7 +342,8 @@ namespace datacoe // Update data GameData updatedData = dm.getGamedata(); - updatedData.setHighscore(200); + std::array updatedScores = {200, 300, 400, 500}; + updatedData.setHighscores(updatedScores); dm.setGamedata(updatedData); // Save with new encryption setting @@ -356,7 +361,8 @@ namespace datacoe // Should load successfully const GameData &data = dm.getGamedata(); ASSERT_EQ(data.getNickname(), "EncryptionChangeTest"); - ASSERT_EQ(data.getHighscore(), 200); + std::array expectedScores = {200, 300, 400, 500}; + ASSERT_EQ(data.getHighscores(), expectedScores); } } catch (const std::exception &e) @@ -381,10 +387,13 @@ namespace datacoe // Create and save an encrypted file DataManager dm; dm.init(m_testFilename, true); // Use encryption - GameData gameData; - gameData.setNickname("EncryptedTest"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + + GameData data; + data.setNickname("EncryptedTest"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()); // Now verify the file is encrypted and isEncrypted() returns true @@ -400,10 +409,13 @@ namespace datacoe // Create unencrypted file DataManager dm; dm.init(m_testFilename, false); // No encryption - GameData gameData; - gameData.setNickname("UnencryptedTest"); - gameData.setHighscore(200); - dm.setGamedata(gameData); + + GameData data; + data.setNickname("UnencryptedTest"); + std::array scores = {200, 300, 400, 500}; + data.setHighscores(scores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()); // Now verify the file is not encrypted and isEncrypted() returns false @@ -420,10 +432,13 @@ namespace datacoe DataManager dm; dm.init(m_testFilename, true); // Encryption on - GameData gameData; - gameData.setNickname("EncryptionStateTest"); - gameData.setHighscore(300); - dm.setGamedata(gameData); + + GameData data; + data.setNickname("EncryptionStateTest"); + std::array scores = {300, 400, 500, 600}; + data.setHighscores(scores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()); } @@ -444,10 +459,13 @@ namespace datacoe DataManager dm; dm.init(m_testFilename, true); // Start with encryption - GameData gameData; - gameData.setNickname("ChangeEncryptionTest"); - gameData.setHighscore(300); - dm.setGamedata(gameData); + + GameData data; + data.setNickname("ChangeEncryptionTest"); + std::array scores = {300, 400, 500, 600}; + data.setHighscores(scores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()); } @@ -461,9 +479,13 @@ namespace datacoe // Change encryption setting and save dm.setEncryption(false); - GameData gameData = dm.getGamedata(); - gameData.setHighscore(400); // Change data - dm.setGamedata(gameData); + + // Get data, update it, and set it back + GameData data = dm.getGamedata(); + std::array updatedScores = {400, 500, 600, 700}; + data.setHighscores(updatedScores); + dm.setGamedata(data); + ASSERT_TRUE(dm.saveGame()); // Save with new encryption setting // After saving, isEncrypted should reflect the new state diff --git a/tests/data_reader_writer_tests.cpp b/tests/data_reader_writer_tests.cpp index 723e548..9d1fbdd 100644 --- a/tests/data_reader_writer_tests.cpp +++ b/tests/data_reader_writer_tests.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "gtest/gtest.h" +#include "datacoe/data_reader_writer.hpp" #include #include #include @@ -36,7 +36,7 @@ namespace datacoe std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Try to clean up the test file - for (int i = 0; i < 5; i++) + for (std::size_t i = 0; i < 5; i++) { try { @@ -60,7 +60,8 @@ namespace datacoe try { // Create test data - GameData gd("TestData", 200); + std::array scores = {200, 300, 400, 500}; + GameData gd("TestData", scores); // Write data to file bool writeResult = DataReaderWriter::writeData(gd, m_testFilename); @@ -75,7 +76,7 @@ namespace datacoe // Verify data ASSERT_EQ(loadedData.value().getNickname(), "TestData"); - ASSERT_EQ(loadedData.value().getHighscore(), 200); + ASSERT_EQ(loadedData.value().getHighscores(), scores); } catch (const std::exception &e) { @@ -88,7 +89,8 @@ namespace datacoe try { // Test with special characters in the nickname - GameData gd("Test@Data#$%^&*", 300); + std::array scores = {300, 400, 500, 600}; + GameData gd("Test@Data#$%^&*", scores); ASSERT_TRUE(DataReaderWriter::writeData(gd, m_testFilename)); @@ -96,7 +98,7 @@ namespace datacoe ASSERT_TRUE(loadedData.has_value()); ASSERT_EQ(loadedData.value().getNickname(), "Test@Data#$%^&*"); - ASSERT_EQ(loadedData.value().getHighscore(), 300); + ASSERT_EQ(loadedData.value().getHighscores(), scores); } catch (const std::exception &e) { @@ -112,7 +114,8 @@ namespace datacoe TEST_F(DataReaderWriterTest, WriteFailInvalidPath) { - GameData gd("TestData", 400); + std::array scores = {400, 500, 600, 700}; + GameData gd("TestData", scores); bool result = DataReaderWriter::writeData(gd, "/invalid/path/file.json"); ASSERT_FALSE(result) << "Expected failure on invalid file path"; } @@ -138,7 +141,8 @@ namespace datacoe try { // Create test data - GameData originalData("AutoDetectTest", 300); + std::array originalScores = {300, 400, 500, 600}; + GameData originalData("AutoDetectTest", originalScores); // Write with encryption bool writeEncryptedResult = DataReaderWriter::writeData(originalData, m_testFilename, true); @@ -153,7 +157,7 @@ namespace datacoe // Verify data was read correctly ASSERT_EQ(loadedEncrypted.value().getNickname(), "AutoDetectTest"); - ASSERT_EQ(loadedEncrypted.value().getHighscore(), 300); + ASSERT_EQ(loadedEncrypted.value().getHighscores(), originalScores); // Now write the same data unencrypted to a new file bool writeUnencryptedResult = DataReaderWriter::writeData(originalData, unencryptedFilename, false); @@ -167,7 +171,7 @@ namespace datacoe // Verify data was read correctly ASSERT_EQ(loadedUnencrypted.value().getNickname(), "AutoDetectTest"); - ASSERT_EQ(loadedUnencrypted.value().getHighscore(), 300); + ASSERT_EQ(loadedUnencrypted.value().getHighscores(), originalScores); } catch (const std::exception &e) { @@ -206,7 +210,8 @@ namespace datacoe try { // Create test data - GameData testData("EncryptionDetectionTest", 400); + std::array scores = {400, 500, 600, 700}; + GameData testData("EncryptionDetectionTest", scores); // Write encrypted data ASSERT_TRUE(DataReaderWriter::writeData(testData, m_testFilename, true)); @@ -262,7 +267,8 @@ namespace datacoe try { // Create and write encrypted data - GameData originalData("EncryptedData", 500); + std::array scores = {500, 600, 700, 800}; + GameData originalData("EncryptedData", scores); ASSERT_TRUE(DataReaderWriter::writeData(originalData, m_testFilename, true)); // Try to read without decryption @@ -272,7 +278,7 @@ namespace datacoe // Verify data ASSERT_EQ(loadedData.value().getNickname(), "EncryptedData"); - ASSERT_EQ(loadedData.value().getHighscore(), 500); + ASSERT_EQ(loadedData.value().getHighscores(), scores); } catch (const std::exception &e) { @@ -285,7 +291,8 @@ namespace datacoe try { // Create and write unencrypted data - GameData originalData("UnencryptedData", 600); + std::array scores = {600, 700, 800, 900}; + GameData originalData("UnencryptedData", scores); ASSERT_TRUE(DataReaderWriter::writeData(originalData, m_testFilename, false)); // Try to read with decryption @@ -295,7 +302,7 @@ namespace datacoe // Verify data ASSERT_EQ(loadedData.value().getNickname(), "UnencryptedData"); - ASSERT_EQ(loadedData.value().getHighscore(), 600); + ASSERT_EQ(loadedData.value().getHighscores(), scores); } catch (const std::exception &e) { diff --git a/tests/error_handling_tests.cpp b/tests/error_handling_tests.cpp index 7376bab..9c56bb1 100644 --- a/tests/error_handling_tests.cpp +++ b/tests/error_handling_tests.cpp @@ -1,8 +1,9 @@ -#include -#include +#include "gtest/gtest.h" +#include "datacoe/data_manager.hpp" #include #include #include +#include #include #ifdef _WIN32 @@ -79,13 +80,13 @@ namespace datacoe // First create a valid file { DataManager dm; - bool initResult = dm.init(m_corruptFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_corruptFilename); - GameData gameData; - gameData.setNickname("ValidData"); - gameData.setHighscore(500); - dm.setGamedata(gameData); + GameData data; + data.setNickname("ValidData"); + std::array scores = {500, 600, 700, 800}; + data.setHighscores(scores); + dm.setGamedata(data); bool saveResult = dm.saveGame(); ASSERT_TRUE(saveResult) << "Failed to create initial file for corruption test"; @@ -107,10 +108,11 @@ namespace datacoe DataManager dm; dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("ReadOnly"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + GameData data; + data.setNickname("ReadOnly"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); bool saveResult = dm.saveGame(); if (!saveResult) @@ -132,10 +134,11 @@ namespace datacoe DataManager dm; dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("ReadOnly"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + GameData data; + data.setNickname("ReadOnly"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); bool saveResult = dm.saveGame(); if (!saveResult) @@ -171,26 +174,26 @@ namespace datacoe // Attempt to load corrupt data DataManager dm; - bool initResult = dm.init(m_corruptFilename); - ASSERT_FALSE(initResult) << "init() should return false for corrupted file"; + dm.init(m_corruptFilename); // Should either initialize with defaults or throw an exception // Either way, the manager should be in a valid state // Just check that we can still use the manager - GameData gameData; - gameData.setNickname("RecoveredData"); - gameData.setHighscore(999); - dm.setGamedata(gameData); + GameData data; + data.setNickname("RecoveredData"); + std::array scores = {999, 999, 999, 999}; + data.setHighscores(scores); + dm.setGamedata(data); + bool saveResult = dm.saveGame(); ASSERT_TRUE(saveResult) << "Failed to save after recovery"; // Try loading again - should work now DataManager dm2; - bool loadResult = dm2.init(m_corruptFilename); - ASSERT_TRUE(loadResult) << "init() should return true after file is repaired"; + dm2.init(m_corruptFilename); ASSERT_EQ(dm2.getGamedata().getNickname(), "RecoveredData"); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 999); + ASSERT_EQ(dm2.getGamedata().getHighscores(), scores); } TEST_F(ErrorHandlingTest, NonExistentDirectory) @@ -198,14 +201,14 @@ namespace datacoe std::string nonExistentPath = "non/existent/directory/file.json"; DataManager dm; - bool initResult = dm.init(nonExistentPath); - ASSERT_FALSE(initResult) << "init() should return false for non-existent directory"; + dm.init(nonExistentPath); // Should still be able to set data - GameData gameData; - gameData.setNickname("TestNonExistent"); - gameData.setHighscore(123); - dm.setGamedata(gameData); + GameData data; + data.setNickname("TestNonExistent"); + std::array scores = {123, 234, 345, 456}; + data.setHighscores(scores); + dm.setGamedata(data); // Save will likely fail but shouldn't crash bool saveResult = dm.saveGame(); @@ -220,14 +223,14 @@ namespace datacoe TEST_F(ErrorHandlingTest, EmptyFilename) { DataManager dm; - bool initResult = dm.init(""); // Empty filename - ASSERT_FALSE(initResult) << "init() should return false for empty filename"; + dm.init(""); // Empty filename // Should still be able to use the manager - GameData gameData; - gameData.setNickname("EmptyFilename"); - gameData.setHighscore(123); - dm.setGamedata(gameData); + GameData data; + data.setNickname("EmptyFilename"); + std::array scores = {123, 234, 345, 456}; + data.setHighscores(scores); + dm.setGamedata(data); // Save may fail but shouldn't crash bool saveResult = dm.saveGame(); @@ -245,13 +248,13 @@ namespace datacoe // Try to save to a read-only file DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_TRUE(initResult) << "init() should return true when loading existing file"; + dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("NewData"); - gameData.setHighscore(200); - dm.setGamedata(gameData); + GameData data; + data.setNickname("NewData"); + std::array scores = {200, 300, 400, 500}; + data.setHighscores(scores); + dm.setGamedata(data); // Save will likely fail but shouldn't crash bool saveResult = dm.saveGame(); @@ -269,13 +272,13 @@ namespace datacoe // First create valid data { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("Original"); - gameData.setHighscore(100); - dm.setGamedata(gameData); + GameData data; + data.setNickname("Original"); + std::array scores = {100, 200, 300, 400}; + data.setHighscores(scores); + dm.setGamedata(data); bool saveResult = dm.saveGame(); ASSERT_TRUE(saveResult) << "Failed to save initial data"; @@ -290,23 +293,23 @@ namespace datacoe // Try to load the truncated file DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for truncated file"; + dm.init(m_testFilename); // Manager should still be usable - GameData gameData; - gameData.setNickname("Recovered"); - gameData.setHighscore(200); - dm.setGamedata(gameData); + GameData data; + data.setNickname("Recovered"); + std::array scores = {200, 300, 400, 500}; + data.setHighscores(scores); + dm.setGamedata(data); + bool saveResult = dm.saveGame(); ASSERT_TRUE(saveResult) << "Failed to save after recovery"; // Verify recovery worked DataManager dm2; - bool loadResult = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true for repaired file"; + dm2.init(m_testFilename); ASSERT_EQ(dm2.getGamedata().getNickname(), "Recovered"); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 200); + ASSERT_EQ(dm2.getGamedata().getHighscores(), scores); } TEST_F(ErrorHandlingTest, MalformedJson) @@ -320,23 +323,23 @@ namespace datacoe // Try to load the malformed file DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for malformed JSON"; + dm.init(m_testFilename); // Verify we can save valid data - GameData gameData; - gameData.setNickname("FixedData"); - gameData.setHighscore(300); - dm.setGamedata(gameData); + GameData data; + data.setNickname("FixedData"); + std::array scores = {300, 400, 500, 600}; + data.setHighscores(scores); + dm.setGamedata(data); + bool saveResult = dm.saveGame(); ASSERT_TRUE(saveResult) << "Failed to save after malformed JSON recovery"; // Check that the data was saved correctly DataManager dm2; - bool loadResult = dm2.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true after saving valid data"; + dm2.init(m_testFilename); ASSERT_EQ(dm2.getGamedata().getNickname(), "FixedData"); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 300); + ASSERT_EQ(dm2.getGamedata().getHighscores(), scores); } } // namespace datacoe \ No newline at end of file diff --git a/tests/game_data_tests.cpp b/tests/game_data_tests.cpp index 8cc044c..be32c72 100644 --- a/tests/game_data_tests.cpp +++ b/tests/game_data_tests.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "gtest/gtest.h" +#include "datacoe/game_data.hpp" +#include namespace datacoe { @@ -7,14 +8,16 @@ namespace datacoe { GameData gd; ASSERT_EQ(gd.getNickname(), ""); - ASSERT_EQ(gd.getHighscore(), 0); + std::array expectedScores = {0, 0, 0, 0}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, ParameterizedConstructor) { - GameData gd("Player1", 500); + std::array scores = {100, 200, 300, 400}; + GameData gd("Player1", scores); ASSERT_EQ(gd.getNickname(), "Player1"); - ASSERT_EQ(gd.getHighscore(), 500); + ASSERT_EQ(gd.getHighscores(), scores); } TEST(GameDataTest, SetAndGetNickname) @@ -32,94 +35,101 @@ namespace datacoe ASSERT_EQ(gd.getNickname(), ""); } - TEST(GameDataTest, SetAndGetHighscore) + TEST(GameDataTest, SetAndGetHighscores) { GameData gd; - gd.setHighscore(300); - ASSERT_EQ(gd.getHighscore(), 300); + std::array scores = {300, 400, 500, 600}; + gd.setHighscores(scores); + ASSERT_EQ(gd.getHighscores(), scores); - // Test changing highscore - gd.setHighscore(400); - ASSERT_EQ(gd.getHighscore(), 400); + // Test changing highscores + std::array newScores = {400, 500, 600, 700}; + gd.setHighscores(newScores); + ASSERT_EQ(gd.getHighscores(), newScores); - // Test zero highscore - gd.setHighscore(0); - ASSERT_EQ(gd.getHighscore(), 0); - - // Test negative highscore (if allowed by your game's rules) - gd.setHighscore(-10); - ASSERT_EQ(gd.getHighscore(), -10); + // Test zero highscores + std::array zeroScores = {0, 0, 0, 0}; + gd.setHighscores(zeroScores); + ASSERT_EQ(gd.getHighscores(), zeroScores); } TEST(GameDataTest, ToJsonBasic) { - GameData gd("JsonTest", 400); + std::array scores = {100, 200, 300, 400}; + GameData gd("JsonTest", scores); json j = gd.toJson(); ASSERT_TRUE(j.is_object()); ASSERT_TRUE(j.contains("nickname")); - ASSERT_TRUE(j.contains("highscore")); + ASSERT_TRUE(j.contains("highscores")); ASSERT_EQ(j["nickname"], "JsonTest"); - ASSERT_EQ(j["highscore"], 400); + + auto highscores = j["highscores"].get>(); + ASSERT_EQ(highscores, scores); } TEST(GameDataTest, ToJsonEmptyNickname) { - GameData gd("", 100); + std::array scores = {100, 200, 300, 400}; + GameData gd("", scores); json j = gd.toJson(); ASSERT_EQ(j["nickname"], ""); - ASSERT_EQ(j["highscore"], 100); + auto highscores = j["highscores"].get>(); + ASSERT_EQ(highscores, scores); } TEST(GameDataTest, FromJsonBasic) { json j; j["nickname"] = "JsonTest"; - j["highscore"] = 400; + j["highscores"] = {100, 200, 300, 400}; GameData gd = GameData::fromJson(j); ASSERT_EQ(gd.getNickname(), "JsonTest"); - ASSERT_EQ(gd.getHighscore(), 400); + std::array expectedScores = {100, 200, 300, 400}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, FromJsonEmptyNickname) { json j; j["nickname"] = ""; - j["highscore"] = 400; + j["highscores"] = {100, 200, 300, 400}; GameData gd = GameData::fromJson(j); ASSERT_EQ(gd.getNickname(), ""); - ASSERT_EQ(gd.getHighscore(), 400); + std::array expectedScores = {100, 200, 300, 400}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, ToAndFromJsonRoundTrip) { - GameData original("RoundTrip", 550); + std::array scores = {150, 250, 350, 450}; + GameData original("RoundTrip", scores); json j = original.toJson(); GameData restored = GameData::fromJson(j); ASSERT_EQ(restored.getNickname(), original.getNickname()); - ASSERT_EQ(restored.getHighscore(), original.getHighscore()); + ASSERT_EQ(restored.getHighscores(), original.getHighscores()); } TEST(GameDataTest, FromJsonMissingNickname) { json j; // Missing nickname field - j["highscore"] = 400; + j["highscores"] = {100, 200, 300, 400}; ASSERT_THROW(GameData::fromJson(j), std::runtime_error); } - TEST(GameDataTest, FromJsonMissingHighscore) + TEST(GameDataTest, FromJsonMissingHighscores) { json j; j["nickname"] = "TestName"; - // Missing highscore field + // Missing highscores field ASSERT_THROW(GameData::fromJson(j), std::runtime_error); } @@ -128,13 +138,28 @@ namespace datacoe { json j1; j1["nickname"] = 12345; // Number instead of string - j1["highscore"] = 400; + j1["highscores"] = {100, 200, 300, 400}; ASSERT_THROW(GameData::fromJson(j1), std::runtime_error); json j2; j2["nickname"] = "TestName"; - j2["highscore"] = "400"; // String instead of number + j2["highscores"] = "Not an array"; // String instead of array + + ASSERT_THROW(GameData::fromJson(j2), std::runtime_error); + } + + TEST(GameDataTest, FromJsonWrongArraySize) + { + json j; + j["nickname"] = "TestName"; + j["highscores"] = {100, 200, 300}; // Only 3 elements instead of 4 + + ASSERT_THROW(GameData::fromJson(j), std::runtime_error); + + json j2; + j2["nickname"] = "TestName"; + j2["highscores"] = {100, 200, 300, 400, 500}; // 5 elements instead of 4 ASSERT_THROW(GameData::fromJson(j2), std::runtime_error); } @@ -143,75 +168,82 @@ namespace datacoe { json j; j["nickname"] = "TestName"; - j["highscore"] = 400; + j["highscores"] = {100, 200, 300, 400}; j["extraField"] = "This should be ignored"; // Extra fields should be ignored GameData gd = GameData::fromJson(j); ASSERT_EQ(gd.getNickname(), "TestName"); - ASSERT_EQ(gd.getHighscore(), 400); + std::array expectedScores = {100, 200, 300, 400}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, FromJsonSpecialCharacters) { json j; j["nickname"] = "Test@#$%^&*()"; - j["highscore"] = 400; + j["highscores"] = {100, 200, 300, 400}; GameData gd = GameData::fromJson(j); ASSERT_EQ(gd.getNickname(), "Test@#$%^&*()"); - ASSERT_EQ(gd.getHighscore(), 400); + std::array expectedScores = {100, 200, 300, 400}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, FromJsonLargeValues) { json j; j["nickname"] = "TestName"; - j["highscore"] = 2147483647; // Max int value + j["highscores"] = {9999999, 9999999, 9999999, 9999999}; // Large values GameData gd = GameData::fromJson(j); - ASSERT_EQ(gd.getHighscore(), 2147483647); + std::array expectedScores = {9999999, 9999999, 9999999, 9999999}; + ASSERT_EQ(gd.getHighscores(), expectedScores); } TEST(GameDataTest, CopyConstructor) { - GameData original("Original", 100); + std::array scores = {100, 200, 300, 400}; + GameData original("Original", scores); GameData copy = original; ASSERT_EQ(copy.getNickname(), "Original"); - ASSERT_EQ(copy.getHighscore(), 100); + ASSERT_EQ(copy.getHighscores(), scores); // Modifying copy shouldn't affect original copy.setNickname("Modified"); - copy.setHighscore(200); + std::array newScores = {500, 600, 700, 800}; + copy.setHighscores(newScores); ASSERT_EQ(original.getNickname(), "Original"); - ASSERT_EQ(original.getHighscore(), 100); + ASSERT_EQ(original.getHighscores(), scores); ASSERT_EQ(copy.getNickname(), "Modified"); - ASSERT_EQ(copy.getHighscore(), 200); + ASSERT_EQ(copy.getHighscores(), newScores); } TEST(GameDataTest, AssignmentOperator) { - GameData original("Original", 100); + std::array scores = {100, 200, 300, 400}; + GameData original("Original", scores); GameData assigned; assigned = original; ASSERT_EQ(assigned.getNickname(), "Original"); - ASSERT_EQ(assigned.getHighscore(), 100); + ASSERT_EQ(assigned.getHighscores(), scores); // Modifying assigned shouldn't affect original assigned.setNickname("Modified"); - assigned.setHighscore(200); + std::array newScores = {500, 600, 700, 800}; + assigned.setHighscores(newScores); ASSERT_EQ(original.getNickname(), "Original"); - ASSERT_EQ(original.getHighscore(), 100); + ASSERT_EQ(original.getHighscores(), scores); ASSERT_EQ(assigned.getNickname(), "Modified"); - ASSERT_EQ(assigned.getHighscore(), 200); + ASSERT_EQ(assigned.getHighscores(), newScores); } } // namespace datacoe \ No newline at end of file diff --git a/tests/integration_tests.cpp b/tests/integration_tests.cpp index 8324cc1..ea8caba 100644 --- a/tests/integration_tests.cpp +++ b/tests/integration_tests.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include "gtest/gtest.h" +#include "datacoe/data_manager.hpp" +#include "datacoe/data_reader_writer.hpp" #include #include #include @@ -36,7 +36,7 @@ namespace datacoe std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Try to clean up the test file - for (int i = 0; i < 5; i++) + for (std::size_t i = 0; i < 5; i++) { try { @@ -60,24 +60,25 @@ namespace datacoe try { // 1. Create game data - GameData originalData("IntegrationTest", 1000); + std::array originalScores = {1000, 2000, 3000, 4000}; + GameData originalData("IntegrationTest", originalScores); // 2. Write directly with DataReaderWriter ASSERT_TRUE(DataReaderWriter::writeData(originalData, m_testFilename)); // 3. Load with DataManager DataManager dm; - bool loadResult = dm.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true when loading an existing file"; + dm.init(m_testFilename); // 4. Verify data loaded correctly const GameData &loadedData = dm.getGamedata(); ASSERT_EQ(loadedData.getNickname(), "IntegrationTest"); - ASSERT_EQ(loadedData.getHighscore(), 1000); + ASSERT_EQ(loadedData.getHighscores(), originalScores); // 5. Modify and save with DataManager GameData updatedData = dm.getGamedata(); - updatedData.setHighscore(2000); + std::array updatedScores = {2000, 3000, 4000, 5000}; + updatedData.setHighscores(updatedScores); dm.setGamedata(updatedData); ASSERT_TRUE(dm.saveGame()); @@ -85,7 +86,7 @@ namespace datacoe std::optional readData = DataReaderWriter::readData(m_testFilename); ASSERT_TRUE(readData.has_value()); ASSERT_EQ(readData.value().getNickname(), "IntegrationTest"); - ASSERT_EQ(readData.value().getHighscore(), 2000); + ASSERT_EQ(readData.value().getHighscores(), updatedScores); } catch (const std::exception &e) { @@ -99,42 +100,41 @@ namespace datacoe { // Create and use multiple DataManager instances with the same file DataManager dm1; - bool initResult1 = dm1.init(m_testFilename); - ASSERT_FALSE(initResult1) << "init() should return false for new file"; + dm1.init(m_testFilename); GameData data1; data1.setNickname("Player1"); - data1.setHighscore(100); + std::array initialScores = {100, 200, 300, 400}; + data1.setHighscores(initialScores); dm1.setGamedata(data1); + ASSERT_TRUE(dm1.saveGame()); // Create a second instance and load the data DataManager dm2; - bool initResult2 = dm2.init(m_testFilename); - ASSERT_TRUE(initResult2) << "init() should return true when loading existing file"; + dm2.init(m_testFilename); ASSERT_EQ(dm2.getGamedata().getNickname(), "Player1"); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 100); + ASSERT_EQ(dm2.getGamedata().getHighscores(), initialScores); // Modify with the second instance GameData data2 = dm2.getGamedata(); - data2.setHighscore(200); + std::array updatedScores = {200, 300, 400, 500}; + data2.setHighscores(updatedScores); dm2.setGamedata(data2); ASSERT_TRUE(dm2.saveGame()); // Create a third instance and check data DataManager dm3; - bool initResult3 = dm3.init(m_testFilename); - ASSERT_TRUE(initResult3) << "init() should return true when loading existing file"; + dm3.init(m_testFilename); ASSERT_EQ(dm3.getGamedata().getNickname(), "Player1"); - ASSERT_EQ(dm3.getGamedata().getHighscore(), 200); + ASSERT_EQ(dm3.getGamedata().getHighscores(), updatedScores); // Original instance should still have old data in memory - ASSERT_EQ(dm1.getGamedata().getHighscore(), 100); + ASSERT_EQ(dm1.getGamedata().getHighscores(), initialScores); // After reloading, it should see the new data - bool loadResult = dm1.loadGame(); - ASSERT_TRUE(loadResult) << "loadGame() should return true when file exists"; - ASSERT_EQ(dm1.getGamedata().getHighscore(), 200); + dm1.loadGame(); + ASSERT_EQ(dm1.getGamedata().getHighscores(), updatedScores); } catch (const std::exception &e) { @@ -148,13 +148,14 @@ namespace datacoe { // Setup initial valid data DataManager dm1; - bool initResult1 = dm1.init(m_testFilename); - ASSERT_FALSE(initResult1) << "init() should return false for new file"; + dm1.init(m_testFilename); + + GameData data; + data.setNickname("ValidData"); + std::array initialScores = {100, 200, 300, 400}; + data.setHighscores(initialScores); + dm1.setGamedata(data); - GameData data1; - data1.setNickname("ValidData"); - data1.setHighscore(100); - dm1.setGamedata(data1); ASSERT_TRUE(dm1.saveGame()); // Corrupt the file @@ -166,30 +167,30 @@ namespace datacoe // Try to load corrupted data DataManager dm2; - bool initResult2 = dm2.init(m_testFilename); - ASSERT_FALSE(initResult2) << "init() should return false for corrupted file"; + dm2.init(m_testFilename); // Should initialize with default empty values ASSERT_EQ(dm2.getGamedata().getNickname(), ""); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 0); + ASSERT_EQ(dm2.getGamedata().getHighscores(), (std::array{0, 0, 0, 0})); // Save new data - GameData data2; - data2.setNickname("RecoveredData"); - data2.setHighscore(300); - dm2.setGamedata(data2); + GameData recoveredData; + recoveredData.setNickname("RecoveredData"); + std::array newScores = {300, 400, 500, 600}; + recoveredData.setHighscores(newScores); + dm2.setGamedata(recoveredData); ASSERT_TRUE(dm2.saveGame()); // Verify the new data was saved correctly DataManager dm3; - bool initResult3 = dm3.init(m_testFilename); - ASSERT_TRUE(initResult3) << "init() should return true when loading the repaired file"; + dm3.init(m_testFilename); ASSERT_EQ(dm3.getGamedata().getNickname(), "RecoveredData"); - ASSERT_EQ(dm3.getGamedata().getHighscore(), 300); + ASSERT_EQ(dm3.getGamedata().getHighscores(), newScores); } catch (const std::exception &e) { FAIL() << "Unexpected exception: " << e.what(); } } + } // namespace datacoe \ No newline at end of file diff --git a/tests/memory_tests.cpp b/tests/memory_tests.cpp index 457416e..4a57c9f 100644 --- a/tests/memory_tests.cpp +++ b/tests/memory_tests.cpp @@ -1,6 +1,7 @@ -#include -#include +#include "gtest/gtest.h" +#include "datacoe/data_manager.hpp" #include +#include #include #include @@ -47,23 +48,18 @@ namespace datacoe TEST_F(MemoryTest, RepeatedCreationAndDestruction) { // This test checks for memory leaks by repeatedly creating and destroying objects - constexpr int iterations = 1000; + constexpr std::size_t iterations = 1000; - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { DataManager dm; - bool initResult = dm.init(m_testFilename); + dm.init(m_testFilename); - // First iteration shouldn't find a file - if (i == 0) - ASSERT_FALSE(initResult) << "First init() should return false for new file"; - else - ASSERT_TRUE(initResult) << "Subsequent init() calls should return true for existing file"; - - GameData gameData; - gameData.setNickname("MemoryTest"); - gameData.setHighscore(i); - dm.setGamedata(gameData); + GameData data; + data.setNickname("MemoryTest"); + std::array scores = {i, i + 1, i + 2, i + 3}; + data.setHighscores(scores); + dm.setGamedata(data); dm.saveGame(); } @@ -73,10 +69,10 @@ namespace datacoe // Verify functionality still works DataManager finalDm; - bool finalLoadResult = finalDm.init(m_testFilename); - ASSERT_TRUE(finalLoadResult) << "Final init() should return true for existing file"; + finalDm.init(m_testFilename); ASSERT_EQ(finalDm.getGamedata().getNickname(), "MemoryTest"); - ASSERT_EQ(finalDm.getGamedata().getHighscore(), iterations - 1); + std::array expectedScores = {iterations - 1, iterations, iterations + 1, iterations + 2}; + ASSERT_EQ(finalDm.getGamedata().getHighscores(), expectedScores); } TEST_F(MemoryTest, LargeDataHandling) @@ -87,16 +83,16 @@ namespace datacoe // Create a DataManager with a large nickname { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); // Generate a large string std::string largeString(dataSize, 'A'); - GameData gameData; - gameData.setNickname(largeString); - gameData.setHighscore(999999); - dm.setGamedata(gameData); + GameData data; + data.setNickname(largeString); + std::array scores = {999999, 999999, 999999, 999999}; + data.setHighscores(scores); + dm.setGamedata(data); ASSERT_TRUE(dm.saveGame()); } @@ -104,59 +100,63 @@ namespace datacoe // Check data was saved correctly { DataManager dm; - bool loadResult = dm.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true for existing file"; + dm.init(m_testFilename); ASSERT_EQ(dm.getGamedata().getNickname().size(), dataSize); - ASSERT_EQ(dm.getGamedata().getHighscore(), 999999); + std::array expectedScores = {999999, 999999, 999999, 999999}; + ASSERT_EQ(dm.getGamedata().getHighscores(), expectedScores); } } TEST_F(MemoryTest, MultipleInstancesWithSameFile) { // Test multiple DataManager instances using the same file - constexpr int instanceCount = 10; + constexpr std::size_t instanceCount = 10; // Create initial data { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("InitialData"); - gameData.setHighscore(1000); - dm.setGamedata(gameData); + GameData data; + data.setNickname("InitialData"); + std::array scores = {1000, 2000, 3000, 4000}; + data.setHighscores(scores); + dm.setGamedata(data); ASSERT_TRUE(dm.saveGame()); } // Create multiple instances all pointing to the same file std::vector> managers; - for (int i = 0; i < instanceCount; i++) + for (std::size_t i = 0; i < instanceCount; i++) { auto dm = std::make_unique(); - bool loadResult = dm->init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true for existing file"; + dm->init(m_testFilename); managers.push_back(std::move(dm)); } // Have each manager modify the data - for (int i = 0; i < instanceCount; i++) + for (std::size_t i = 0; i < instanceCount; i++) { - GameData gameData; - gameData.setNickname("Manager" + std::to_string(i)); - gameData.setHighscore(2000 + i); - managers[i]->setGamedata(gameData); + GameData data; + data.setNickname("Manager" + std::to_string(i)); + std::array scores = {2000 + i, 3000 + i, 4000 + i, 5000 + i}; + data.setHighscores(scores); + managers[i]->setGamedata(data); ASSERT_TRUE(managers[i]->saveGame()); } // Check the final state { DataManager dm; - bool loadResult = dm.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true for existing file"; + dm.init(m_testFilename); ASSERT_EQ(dm.getGamedata().getNickname(), "Manager" + std::to_string(instanceCount - 1)); - ASSERT_EQ(dm.getGamedata().getHighscore(), 2000 + instanceCount - 1); + std::array expectedScores = { + 2000 + instanceCount - 1, + 3000 + instanceCount - 1, + 4000 + instanceCount - 1, + 5000 + instanceCount - 1}; + ASSERT_EQ(dm.getGamedata().getHighscores(), expectedScores); } // Release all managers @@ -165,10 +165,10 @@ namespace datacoe // Verify file access still works { DataManager dm; - bool finalLoadResult = dm.init(m_testFilename); - ASSERT_TRUE(finalLoadResult) << "init() should return true for existing file"; + dm.init(m_testFilename); const GameData &data = dm.getGamedata(); ASSERT_FALSE(data.getNickname().empty()); } } + } // namespace datacoe \ No newline at end of file diff --git a/tests/performance_tests.cpp b/tests/performance_tests.cpp index dd9734d..79e2875 100644 --- a/tests/performance_tests.cpp +++ b/tests/performance_tests.cpp @@ -1,12 +1,14 @@ -#include +#include "gtest/gtest.h" #include #include #include +#include #include #include #include #include #include +#include namespace datacoe { @@ -62,24 +64,29 @@ namespace datacoe constexpr int iterations = 100; DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("PerformanceTest"); - gameData.setHighscore(10000); - dm.setGamedata(gameData); + GameData initialData; + initialData.setNickname("PerformanceTest"); + std::array baseScores = {10000, 20000, 30000, 40000}; + initialData.setHighscores(baseScores); + dm.setGamedata(initialData); std::vector timings; timings.reserve(iterations); // Measure save performance - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { // Change data slightly each iteration - GameData updatedData = dm.getGamedata(); - updatedData.setHighscore(10000 + i); - dm.setGamedata(updatedData); + GameData data = dm.getGamedata(); + std::array scores = { + baseScores[0] + i, + baseScores[1] + i, + baseScores[2] + i, + baseScores[3] + i}; + data.setHighscores(scores); + dm.setGamedata(data); auto duration = measureExecutionTime([&]() { dm.saveGame(); }); @@ -120,13 +127,13 @@ namespace datacoe // First create a file to load { DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); - GameData gameData; - gameData.setNickname("PerformanceTest"); - gameData.setHighscore(10000); - dm.setGamedata(gameData); + GameData data; + data.setNickname("PerformanceTest"); + std::array scores = {10000, 20000, 30000, 40000}; + data.setHighscores(scores); + dm.setGamedata(data); dm.saveGame(); } @@ -135,13 +142,12 @@ namespace datacoe timings.reserve(iterations); // Measure load performance - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { auto duration = measureExecutionTime([&]() { DataManager dm; - bool loadResult = dm.init(m_testFilename); - ASSERT_TRUE(loadResult) << "init() should return true when loading existing file"; + dm.init(m_testFilename); // Force load by accessing game data auto data = dm.getGamedata(); }); timings.push_back(duration); @@ -176,21 +182,20 @@ namespace datacoe constexpr int iterations = 500; DataManager dm; - bool initResult = dm.init(m_testFilename); - ASSERT_FALSE(initResult) << "init() should return false for new file"; + dm.init(m_testFilename); // Random generator for mixed operations std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> opDist(0, 2); // 0=save, 1=load, 2=new game - std::uniform_int_distribution<> scoreDist(0, 100000); + std::uniform_int_distribution scoreDist(0, 100000); std::vector names = {"Player1", "Player2", "Player3", "Gamer", "Pro", "Noob", "Champion"}; std::uniform_int_distribution<> nameDist(0, static_cast(names.size() - 1)); auto start = std::chrono::high_resolution_clock::now(); - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { int operation = opDist(gen); @@ -198,10 +203,12 @@ namespace datacoe { case 0: // Save { - GameData gameData; - gameData.setNickname(names[nameDist(gen)]); - gameData.setHighscore(scoreDist(gen)); - dm.setGamedata(gameData); + GameData data; + data.setNickname(names[nameDist(gen)]); + std::array scores = { + scoreDist(gen), scoreDist(gen), scoreDist(gen), scoreDist(gen)}; + data.setHighscores(scores); + dm.setGamedata(data); dm.saveGame(); break; } @@ -224,15 +231,15 @@ namespace datacoe // Verify the manager is still functional after stress GameData finalData; finalData.setNickname("FinalCheck"); - finalData.setHighscore(12345); + std::array finalScores = {12345, 23456, 34567, 45678}; + finalData.setHighscores(finalScores); dm.setGamedata(finalData); ASSERT_TRUE(dm.saveGame()); DataManager dm2; - bool finalLoadResult = dm2.init(m_testFilename); - ASSERT_TRUE(finalLoadResult) << "init() should return true after saving final data"; + dm2.init(m_testFilename); ASSERT_EQ(dm2.getGamedata().getNickname(), "FinalCheck"); - ASSERT_EQ(dm2.getGamedata().getHighscore(), 12345); + ASSERT_EQ(dm2.getGamedata().getHighscores(), finalScores); } TEST_F(PerformanceTest, EncryptionPerformanceComparison) @@ -240,7 +247,8 @@ namespace datacoe constexpr int iterations = 50; // Setup test data - GameData testData("PerformanceTest", 12345); + std::array scores = {12345, 23456, 34567, 45678}; + GameData testData("PerformanceTest", scores); std::string encryptedFilename = m_testFilename + ".encrypted"; std::string unencryptedFilename = m_testFilename + ".unencrypted"; @@ -261,24 +269,30 @@ namespace datacoe ASSERT_TRUE(DataReaderWriter::writeData(testData, unencryptedFilename, false)); // Measure save performance - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { // Modify data slightly to avoid caching effects - testData.setHighscore(12345 + i); + GameData modifiedData = testData; + std::array modifiedScores = { + scores[0] + i, + scores[1] + i, + scores[2] + i, + scores[3] + i}; + modifiedData.setHighscores(modifiedScores); // Measure encrypted save auto encryptedSaveTime = measureExecutionTime([&]() - { DataReaderWriter::writeData(testData, encryptedFilename, true); }); + { DataReaderWriter::writeData(modifiedData, encryptedFilename, true); }); encryptedSaveTimings.push_back(encryptedSaveTime); // Measure unencrypted save auto unencryptedSaveTime = measureExecutionTime([&]() - { DataReaderWriter::writeData(testData, unencryptedFilename, false); }); + { DataReaderWriter::writeData(modifiedData, unencryptedFilename, false); }); unencryptedSaveTimings.push_back(unencryptedSaveTime); } // Measure load performance - for (int i = 0; i < iterations; i++) + for (std::size_t i = 0; i < iterations; i++) { // Measure encrypted load auto encryptedLoadTime = measureExecutionTime([&]()