Skip to content

Conversation

@AenBleidd
Copy link
Member

No description provided.

Copilot AI review requested due to automatic review settings November 1, 2025 22:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds unit tests for the BOINC Custom Action (boinccas) installer component, specifically testing the CAAnnounceUpgrade function. The tests use a helper library to load the DLL dynamically and mock MSI database operations.

  • Adds unit test infrastructure for testing boinccas installer custom actions
  • Integrates Windows Installer Library (WIL) for RAII resource management
  • Configures conditional compilation to enable boinccas tests in CI

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
win_build/unittests.vcxproj Adds boinccas test files, MSI-related library dependencies, and conditional preprocessor definition
win_build/installer.vcxproj Refactors dependency organization by consolidating common dependencies
win_build/boinc.sln Adds installer project as dependency for unittests and reorders dependencies
tests/unit-tests/boinccas/test_boinccas_CAAnnounceUpgrade.cpp Implements unit test for AnnounceUpgrade custom action
tests/unit-tests/boinccas/boinccas_helper.h Declares helper functions and classes for MSI and registry operations
tests/unit-tests/boinccas/boinccas_helper.cpp Implements MSI database and registry manipulation helpers
3rdParty/vcpkg_ports/configs/msbuild/vcpkg.json Adds WIL dependency for Windows resource management
.github/workflows/windows.yml Enables BOINCCAS_TEST preprocessor flag in CI builds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 45 to 47
void MsiHelper::createTable(const std::string_view& sql_create) {
MSIHANDLE hView;
auto result = MsiDatabaseOpenView(hMsi, sql_create.data(), &hView);
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MSIHANDLE hView is not being closed on all error paths. If MsiDatabaseOpenView succeeds but MsiViewExecute fails (lines 52-56), or if MsiViewExecute succeeds but MsiViewClose fails (lines 57-61), the handle will leak. Wrap hView with a RAII wrapper or use a unique_ptr with a custom deleter, or ensure MsiCloseHandle(hView) is called before throwing exceptions.

Copilot uses AI. Check for mistakes.
Comment on lines 76 to 77
MSIHANDLE hView;
auto result = MsiDatabaseOpenView(hMsi, sql_insert.data(), &hView);
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MSIHANDLE hView is not being closed on error paths in the loop (lines 82-108). If any operation within the loop throws an exception, hView will leak. Wrap hView with a RAII wrapper or ensure it's closed in all error paths.

Copilot uses AI. Check for mistakes.
std::to_string(result));
}
for (const auto& record : properties) {
const auto hRecord = MsiCreateRecord(static_cast<UINT>(2));
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The explicit cast static_cast<UINT>(2) is unnecessary since 2 can be directly passed as a UINT literal (2u) or the literal 2 will be implicitly converted. Consider using MsiCreateRecord(2) for cleaner code.

Suggested change
const auto hRecord = MsiCreateRecord(static_cast<UINT>(2));
const auto hRecord = MsiCreateRecord(2);

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 1, 2025 23:09
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +163 to +164
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RegDeleteKey function is being called while a handle to the key is still open. The key handle should be closed before attempting to delete the key. Additionally, RegDeleteKey only deletes empty keys; use RegDeleteTree to delete a key with subkeys, or ensure the key is empty before deletion.

Suggested change
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
RegCloseKey(hKey);
RegDeleteTree(HKEY_LOCAL_MACHINE, registryKey);

Copilot uses AI. Check for mistakes.
NULL
);
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE + 3;
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using magic numbers (3, 4) added to ERROR_INSTALL_FAILURE reduces code readability. Consider defining named constants like ERROR_REGISTRY_CREATE_FAILED = ERROR_INSTALL_FAILURE + 3 to make the error codes self-documenting.

Copilot uses AI. Check for mistakes.

RegCloseKey(hkSetupHive);
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE + 4;
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using magic numbers (3, 4) added to ERROR_INSTALL_FAILURE reduces code readability. Consider defining named constants like ERROR_REGISTRY_SET_FAILED = ERROR_INSTALL_FAILURE + 4 to make the error codes self-documenting.

Copilot uses AI. Check for mistakes.
strMessage.c_str()
);
return ERROR_INSTALL_FAILURE;
return ERROR_INSTALL_FAILURE + 1;
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using magic numbers (1, 2) added to ERROR_INSTALL_FAILURE reduces code readability. Consider defining named constants like ERROR_PROPERTY_GET_FAILED = ERROR_INSTALL_FAILURE + 1 to make the error codes self-documenting.

Copilot uses AI. Check for mistakes.
);
if ( lpszBuffer ) free( lpszBuffer );
return ERROR_INSTALL_FAILURE;
return ERROR_INSTALL_FAILURE + 2;
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using magic numbers (1, 2) added to ERROR_INSTALL_FAILURE reduces code readability. Consider defining named constants like ERROR_PROPERTY_BUFFER_FAILED = ERROR_INSTALL_FAILURE + 2 to make the error codes self-documenting.

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 1, 2025 23:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +123 to +124
constexpr auto registryKey =
"SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup";
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The registry key string literal is split across two lines, which may cause compilation issues. Consider placing the entire string on line 124 or using proper line continuation syntax.

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 04:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

tests/unit-tests/boinccas/boinccas_helper.cpp:1

  • The createPropertiesTable() method is called in init() at line 40, but createPropertiesTable is declared as a public method in the header. Since init() is now being used and creates the Properties table during initialization, the test at line 55 of test_boinccas_CAAnnounceUpgrade.cpp should not call createPropertiesTable() again as it will fail trying to create an already-existing table.
// This file is part of BOINC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 35 to 37
if (hMsi != 0) {
MsiCloseHandle(hMsi);
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MSI handle cleanup at line 55-57 duplicates the cleanup logic already present in the destructor (lines 35-37). The handle will be closed again in the destructor after this test completes, resulting in a double-close. Remove this redundant cleanup block or set hMsi to 0 after closing it.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +50
const std::vector<std::pair<std::string, std::string>>& properties);
std::string getMsiHandle() const {
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing include directive for <vector>. The method signature uses std::vector but the required header is not included.

Copilot uses AI. Check for mistakes.
}
result = MsiSummaryInfoSetProperty(hSummaryInfo, 9, VT_LPSTR, 0, nullptr,
"{2C4296B7-9E88-4CD8-9FC6-26CE7B053ED1}");
if (result != ERROR_SUCCESS) {
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of RegDeleteKey is not checked. If the key deletion fails, the function silently continues. Consider checking the result for proper error handling or logging.

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 05:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (result != ERROR_SUCCESS) {
throw std::runtime_error("Error closing view: " +
std::to_string(result));
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: hView handle is not closed with MsiCloseHandle() after MsiViewClose(). According to MSI documentation, both MsiViewClose() and MsiCloseHandle() must be called on view handles. Add MsiCloseHandle(hView) after line 78.

Suggested change
}
}
MsiCloseHandle(hView);

Copilot uses AI. Check for mistakes.
Comment on lines 98 to 103
MSIHANDLE hView;
auto result = MsiDatabaseOpenView(hMsi, sql_insert.data(), &hView);
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Error creating view: " +
std::to_string(result));
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: hView handle is not closed with MsiCloseHandle() if an exception is thrown in the loop (lines 104-130) or after MsiViewClose() succeeds. Add MsiCloseHandle(hView) after line 136, similar to how hRecord is handled with MsiCloseHandle at line 125.

Copilot uses AI. Check for mistakes.
EXPECT_NE(expectedVersion, getRegistryValue("UpgradingTo"));

if (hMsi != 0) {
MsiCloseHandle(hMsi);
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hMsi handle should be set to 0 after closing to prevent double-close in the destructor. Add 'hMsi = 0;' after line 56.

Suggested change
MsiCloseHandle(hMsi);
MsiCloseHandle(hMsi);
hMsi = 0;

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 06:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

std::to_string(result));
}
result = MsiViewExecute(hView, 0);
if (result != ERROR_SUCCESS) {
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: hView is not closed if MsiViewExecute fails. The handle created by MsiDatabaseOpenView at line 64 should be closed with MsiCloseHandle(hView) before throwing the exception at line 71.

Suggested change
if (result != ERROR_SUCCESS) {
if (result != ERROR_SUCCESS) {
MsiCloseHandle(hView);

Copilot uses AI. Check for mistakes.
Comment on lines 98 to 118
MSIHANDLE hView;
auto result = MsiDatabaseOpenView(hMsi, sql_insert.data(), &hView);
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Error creating view: " +
std::to_string(result));
}
for (const auto& record : properties) {
const auto hRecord = MsiCreateRecord(2);
if (hRecord == 0) {
throw std::runtime_error("Failed to create record");
}
result = MsiRecordSetString(hRecord, 1, record.first.c_str());
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Failed to set record, errorcode: " +
std::to_string(result));
}
result = MsiRecordSetString(hRecord, 2, record.second.c_str());
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Failed to set record, errorcode: " +
std::to_string(result));
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: hView is not closed if an exception is thrown within the loop (lines 107, 112, 117). Consider using RAII wrappers or adding proper cleanup in exception paths before throwing.

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +115
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Failed to set record, errorcode: " +
std::to_string(result));
}
result = MsiRecordSetString(hRecord, 2, record.second.c_str());
if (result != ERROR_SUCCESS) {
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: hRecord is not closed if MsiRecordSetString fails at line 110. The handle created at line 105 should be closed with MsiCloseHandle(hRecord) before throwing the exception at line 112.

Suggested change
if (result != ERROR_SUCCESS) {
throw std::runtime_error("Failed to set record, errorcode: " +
std::to_string(result));
}
result = MsiRecordSetString(hRecord, 2, record.second.c_str());
if (result != ERROR_SUCCESS) {
if (result != ERROR_SUCCESS) {
MsiCloseHandle(hRecord);
throw std::runtime_error("Failed to set record, errorcode: " +
std::to_string(result));
}
result = MsiRecordSetString(hRecord, 2, record.second.c_str());
if (result != ERROR_SUCCESS) {
MsiCloseHandle(hRecord);

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 07:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
}
AnnounceUpgradeFn hFunc = nullptr;
MSIHANDLE hMsi = 0;
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The msiHelper member variable is instantiated before hDll and hFunc are initialized in the constructor. Since MsiHelper creates an MSI database during construction and the test fixture's constructor then calls load_function_from_boinccas which may require the DLL to be present, this ordering could lead to issues. Consider moving msiHelper instantiation to after the DLL loading, or use a smart pointer to delay its construction.

Copilot uses AI. Check for mistakes.
Comment on lines +232 to +239
HKEY hKey = nullptr;
const auto openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKey, 0,
KEY_WRITE, &hKey);
if (openResult != ERROR_SUCCESS) {
return;
}
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order of operations is incorrect. RegDeleteKey is called while hKey is still open, and then RegCloseKey is called on a potentially invalid handle. The key should be closed before attempting to delete it. Additionally, RegDeleteKey should use hKey as the first parameter, not HKEY_LOCAL_MACHINE, since the key is already opened.

Suggested change
HKEY hKey = nullptr;
const auto openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKey, 0,
KEY_WRITE, &hKey);
if (openResult != ERROR_SUCCESS) {
return;
}
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
// To delete a registry key, open its parent and call RegDeleteKey with the subkey name.
constexpr auto parentKeyPath = "SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley";
constexpr auto subKeyName = "BOINC Setup";
HKEY hParentKey = nullptr;
const auto openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, parentKeyPath, 0,
KEY_WRITE, &hParentKey);
if (openResult != ERROR_SUCCESS) {
return;
}
RegCloseKey(hParentKey); // Close before deleting
// Reopen parent for deletion (RegDeleteKey requires open parent)
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, parentKeyPath, 0, KEY_WRITE, &hParentKey) == ERROR_SUCCESS) {
RegDeleteKey(hParentKey, subKeyName);
RegCloseKey(hParentKey);
}

Copilot uses AI. Check for mistakes.
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 09:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

tests/unit-tests/boinccas/test_boinccas_CAAnnounceUpgrade.cpp:1

  • The preprocessor directive should be #ifdef BOINCCAS_TEST instead of #ifndef BOINCCAS_TEST. With #ifndef, tests are excluded when BOINCCAS_TEST is defined, which is opposite to the intended behavior. The build sets -p:BOINCCAS_TEST=true to enable these tests.
// This file is part of BOINC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Vitalii Koshura <[email protected]>
Signed-off-by: Vitalii Koshura <[email protected]>
Copilot AI review requested due to automatic review settings November 2, 2025 17:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

std::filesystem::remove(std::filesystem::current_path() / msiName);
}
catch (const std::exception& ex) {
throw std::runtime_error( "Failed to remove existing MSI file: " +
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space after opening parenthesis. Should be std::runtime_error( without the space.

Suggested change
throw std::runtime_error( "Failed to remove existing MSI file: " +
throw std::runtime_error("Failed to remove existing MSI file: " +

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +65
try {
std::filesystem::remove(std::filesystem::current_path() / msiName);
}
catch (const std::exception& ex) {
throw std::runtime_error( "Failed to remove existing MSI file: " +
std::string(ex.what()));
}
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rethrowing exceptions in cleanup code can mask the original issue. The cleanup() method is called from the destructor (line 30), where exceptions should not be thrown. Consider using std::filesystem::remove with the std::error_code overload instead of the throwing version, or catch and log the error without rethrowing.

Suggested change
try {
std::filesystem::remove(std::filesystem::current_path() / msiName);
}
catch (const std::exception& ex) {
throw std::runtime_error( "Failed to remove existing MSI file: " +
std::string(ex.what()));
}
std::error_code ec;
std::filesystem::remove(std::filesystem::current_path() / msiName, ec);
if (ec) {
// Optionally log the error, but do not throw
OutputDebugStringA(("Failed to remove existing MSI file: " + ec.message()).c_str());
}

Copilot uses AI. Check for mistakes.
CAAnnounceUpgrade(MSIHANDLE hMSIHandle);
~CAAnnounceUpgrade();
virtual UINT OnExecution();
UINT OnExecution() override final;
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using both override and final is redundant for documentation purposes. While technically correct, final implies override, so using both is unnecessary. Consider using only final or keeping just override if the method might be overridden in derived classes (though that seems unlikely here).

Suggested change
UINT OnExecution() override final;
UINT OnExecution() final;

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings November 3, 2025 02:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

std::filesystem::remove(std::filesystem::current_path() / msiName);
}
catch (const std::exception& ex) {
throw std::runtime_error( "Failed to remove existing MSI file: " +
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space after opening parenthesis in throw statement. Should be 'throw std::runtime_error("Failed' without the space.

Copilot uses AI. Check for mistakes.
TEST_F(test_boinccas_CACleanupOldBinaries,
CleanupOldBinaries_NonExistent_INSTALLDIR_Directory) {
const auto dir =
std::filesystem::current_path() /= "non_existent_directory";
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using compound assignment operator '/=' modifies the current_path() temporary, but the result is not what's intended. This should use the '/' operator instead: 'std::filesystem::current_path() / "non_existent_directory"' without the '=' to create a new path without modifying anything.

Suggested change
std::filesystem::current_path() /= "non_existent_directory";
std::filesystem::current_path() / "non_existent_directory";

Copilot uses AI. Check for mistakes.

TEST_F(test_boinccas_CACleanupOldBinaries,
CleanupOldBinaries_Empty_INSTALLDIR_Directory) {
testDir = std::filesystem::current_path() /= "empty";
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using compound assignment operator '/=' modifies the current_path() temporary. This should use the '/' operator instead: 'std::filesystem::current_path() / "empty"' without the '='.

Suggested change
testDir = std::filesystem::current_path() /= "empty";
testDir = std::filesystem::current_path() / "empty";

Copilot uses AI. Check for mistakes.

TEST_F(test_boinccas_CACleanupOldBinaries,
CleanupOldBinaries_NonEmpty_INSTALLDIR_Directory_RemoveAllListedFiles) {
testDir = std::filesystem::current_path() /= "non_empty";
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using compound assignment operator '/=' modifies the current_path() temporary. This should use the '/' operator instead: 'std::filesystem::current_path() / "non_empty"' without the '='.

Copilot uses AI. Check for mistakes.

TEST_F(test_boinccas_CACleanupOldBinaries,
CleanupOldBinaries_NonEmpty_INSTALLDIR_Directory_KeepUnListedFiles) {
testDir = std::filesystem::current_path() /= "non_empty";
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using compound assignment operator '/=' modifies the current_path() temporary. This should use the '/' operator instead: 'std::filesystem::current_path() / "non_empty"' without the '='.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings November 4, 2025 04:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +232 to +239
HKEY hKey = nullptr;
const auto openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKey, 0,
KEY_WRITE, &hKey);
if (openResult != ERROR_SUCCESS) {
return;
}
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key handle is closed after attempting to delete the key, but RegDeleteKey should be called with the parent key handle (HKEY_LOCAL_MACHINE), not the opened subkey handle. Also, the opened key handle should be closed before attempting deletion. The current code may leak the handle if RegDeleteKey succeeds.

Suggested change
HKEY hKey = nullptr;
const auto openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKey, 0,
KEY_WRITE, &hKey);
if (openResult != ERROR_SUCCESS) {
return;
}
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);
RegCloseKey(hKey);
RegDeleteKey(HKEY_LOCAL_MACHINE, registryKey);

Copilot uses AI. Check for mistakes.
Comment on lines 116 to 129
//TEST_F(test_boinccas_CACreateAcctMgrLoginFile,
// Empty_DATADIR_Directory_And_ACCTMGR_LOGIN_Property_Set) {
// PMSIHANDLE hMsi;
// const auto dir = std::filesystem::current_path() /= "test_data";
// msiHelper.insertProperties({
// {"DATADIR", dir.string().c_str()},
// {"ACCTMGR_LOGIN", "testuser"}
// });
// const auto result = MsiOpenPackage(msiHelper.getMsiHandle().c_str(),
// &hMsi);
// ASSERT_EQ(0u, result);

// EXPECT_EQ(0u, hFunc(hMsi));
//}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This large commented-out test case should either be uncommented and fixed (if intended for future use), or removed entirely to reduce code clutter.

Suggested change
//TEST_F(test_boinccas_CACreateAcctMgrLoginFile,
// Empty_DATADIR_Directory_And_ACCTMGR_LOGIN_Property_Set) {
// PMSIHANDLE hMsi;
// const auto dir = std::filesystem::current_path() /= "test_data";
// msiHelper.insertProperties({
// {"DATADIR", dir.string().c_str()},
// {"ACCTMGR_LOGIN", "testuser"}
// });
// const auto result = MsiOpenPackage(msiHelper.getMsiHandle().c_str(),
// &hMsi);
// ASSERT_EQ(0u, result);
// EXPECT_EQ(0u, hFunc(hMsi));
//}

Copilot uses AI. Check for mistakes.
&hMsi);
ASSERT_EQ(0u, result);
EXPECT_EQ(0u, hFunc(hMsi));
// verify that the directory is now empty
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on line 150 is incorrect. The test expects the directory to NOT be empty (EXPECT_FALSE), so the comment should say 'verify that the directory is not empty' or 'verify that unlisted files remain'.

Suggested change
// verify that the directory is now empty
// verify that the directory is not empty (unlisted files remain)

Copilot uses AI. Check for mistakes.
Comment on lines 20 to +21
<PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(BOINCCAS_TEST)' == 'true'">BOINCCAS_TEST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having two separate PreprocessorDefinitions elements can lead to the second one overriding the first. Consider consolidating them into a single element or ensuring the conditional definition properly appends to the base definitions.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings November 5, 2025 00:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

_T(" <password_hash>%s</password_hash>\n")
_T("</acct_mgr_login>\n"),
strAcctMgrLogin.c_str(),
strAcctMgrPasswordHash.c_str()
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null pointer dereference when strAcctMgrPasswordHash is empty. The previous implementation explicitly checked if the string was empty and used an empty string literal. This change directly uses .c_str() which, while safe for empty strings in practice, removes the explicit semantic that an empty password hash should result in an empty XML element value. Consider restoring the original conditional logic: !strAcctMgrPasswordHash.empty() ? strAcctMgrPasswordHash.c_str() : _T(\"\")

Suggested change
strAcctMgrPasswordHash.c_str()
!strAcctMgrPasswordHash.empty() ? strAcctMgrPasswordHash.c_str() : _T("")

Copilot uses AI. Check for mistakes.
return uiReturnValue;
}

// The project_init.xml file is stored in the data directory.
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment incorrectly references 'project_init.xml' when the code actually creates 'acct_mgr_login.xml'. Update comment to: 'The acct_mgr_login.xml file is stored in the data directory.'

Suggested change
// The project_init.xml file is stored in the data directory.
// The acct_mgr_login.xml file is stored in the data directory.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +64
throw std::runtime_error( "Failed to remove existing MSI file: " +
std::string(ex.what()));
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception is thrown in cleanup() which is called from the destructor. Throwing exceptions from destructors can lead to program termination if another exception is already in flight. Consider logging the error instead of throwing, or silently catch and ignore the exception since this is a cleanup operation.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant