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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ public interface WindowsHelper {
*/
String getRegistryValue(String path, String key);

/**
* @param appName the application name to search for in the Windows registry.
* @return the DisplayName entry if the application is found in the Windows registry or {@code null} if nothing was found.
Comment thread
jakozian marked this conversation as resolved.
*/
String getDisplayNameFromRegistry(String appName);

/**
* @param appName the application name to search for in the Windows registry.
* @return the DisplayIcon entry if the application is found in the Windows registry or {@code null} if nothing was found.
*/
String getDisplayIconFromRegistry(String appName);

/**
* @param appName the application name to search for in the Windows registry.
* @return the UninstallString entry if the application is found in the Windows registry or {@code null} if nothing was found.
*/
String getUninstallStringFromRegistry(String appName);

/**
* @param appName the application name to search for in the Windows registry.
* @return the InstallLocation entry if the application is found in the Windows registry or {@code null} if nothing was found.
*/
String getInstallLocationFromRegistry(String appName);

/**
* @param context the {@link IdeContext}.
* @return the instance of {@link WindowsHelper}.
Expand Down
60 changes: 57 additions & 3 deletions cli/src/main/java/com/devonfw/tools/ide/os/WindowsHelperImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ public class WindowsHelperImpl implements WindowsHelper {
/** Registry key for the users environment variables. */
public static final String HKCU_ENVIRONMENT = "HKCU\\Environment";

/** Common Windows registry base paths containing (uninstall) information for installed applications (system-wide and per-user). */
private static final String[] REGISTRY_BASE_PATHS = {
"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
"HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
};

private final IdeContext context;

/**
Expand Down Expand Up @@ -60,13 +67,60 @@ public String getUserEnvironmentValue(String key) {
@Override
public String getRegistryValue(String path, String key) {

ProcessResult result = this.context.newProcess().errorHandling(ProcessErrorHandling.LOG_WARNING).executable("reg").addArgs("query", path, "/v", key)
List<String> out = runReg("query", path, "/v", key);
if (out != null) {
return retrieveRegString(key, out);
}
return null;
}

@Override
public String getDisplayNameFromRegistry(String appName) {
return getRegistryValueBySearch(appName, "DisplayName");
}

@Override
public String getDisplayIconFromRegistry(String appName) {
return getRegistryValueBySearch(appName, "DisplayIcon");
}

@Override
public String getUninstallStringFromRegistry(String appName) {
return getRegistryValueBySearch(appName, "UninstallString");
}

@Override
public String getInstallLocationFromRegistry(String appName) {
return getRegistryValueBySearch(appName, "InstallLocation");
}

private String getRegistryValueBySearch(String appName, String key) {

for (String registryBasePath : REGISTRY_BASE_PATHS) {
List<String> out = runReg("query", registryBasePath, "/s", "/f", appName);
if (out != null) {
Comment thread
jakozian marked this conversation as resolved.
Outdated
return retrieveRegString(key, out);
}
}
return null;
}

/**
* Executes a Windows registry command and returns its output.
*
* @param args the registry command arguments.
* @return the command output lines, or {@code null} if the command failed
*/
protected List<String> runReg(String... args) {
ProcessResult result = this.context.newProcess()
.errorHandling(ProcessErrorHandling.LOG_WARNING)
.executable("reg")
.addArgs(args)
.run(ProcessMode.DEFAULT_CAPTURE);
if (!result.isSuccessful()) {
return null;
}
List<String> out = result.getOut();
return retrieveRegString(key, out);
return result.getOut();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
*/
class WindowsHelperImplTest extends AbstractIdeContextTest {

private static final String TEST_APP_NAME = "TestApp";

private static final String UNKNOWN_TEST_APP_NAME = "UnknownApp";

/**
* Tests if the USER_PATH registry entry can be parsed properly.
*/
Expand Down Expand Up @@ -48,4 +52,47 @@ void testWindowsHelperParseEmptyRegStringReturnsNull() {
assertThat(regString).isNull();
}

/**
* Tests if correct keys can be found in registry output for app name filter.
*/
@Test
void testRegistryLookupReturnsCorrectEntryIfFound() {
Comment thread
jakozian marked this conversation as resolved.
// arrange
AbstractIdeTestContext context = new IdeTestContext();
WindowsHelperImpl helper = new WindowsHelperImplTestable(context);

// act
String displayName = helper.getDisplayNameFromRegistry(TEST_APP_NAME);
String icon = helper.getDisplayIconFromRegistry(TEST_APP_NAME);
String uninstall = helper.getUninstallStringFromRegistry(TEST_APP_NAME);
String location = helper.getInstallLocationFromRegistry(TEST_APP_NAME);

// assert
assertThat(displayName).isEqualTo("Test Application");
assertThat(icon).isEqualTo("C:\\Program Files\\TestApp\\testapp.exe,0");
assertThat(uninstall).isEqualTo("\"C:\\Program Files\\TestApp\\uninstall.exe\"");
assertThat(location).isEqualTo("C:\\Program Files\\TestApp");
}

/**
* Tests if registry lookup return nulls on unknown app name filter.
*/
@Test
void testRegistryLookupReturnsNullIfNotFound() {
// arrange
AbstractIdeTestContext context = new IdeTestContext();
WindowsHelperImpl helper = new WindowsHelperImplTestable(context);

// act
String displayName = helper.getDisplayNameFromRegistry(UNKNOWN_TEST_APP_NAME);
String icon = helper.getDisplayIconFromRegistry(UNKNOWN_TEST_APP_NAME);
String uninstall = helper.getUninstallStringFromRegistry(UNKNOWN_TEST_APP_NAME);
String location = helper.getInstallLocationFromRegistry(UNKNOWN_TEST_APP_NAME);

// assert
assertThat(displayName).isNull();
assertThat(icon).isNull();
assertThat(uninstall).isNull();
assertThat(location).isNull();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.devonfw.tools.ide.os;

import java.util.List;

import com.devonfw.tools.ide.context.IdeContext;

/**
* Test-specific subclass of {@link WindowsHelperImpl}.
*
* <p>
* Mainly used as a test seam to simulate the reg.exe command for test purposes.
* </p>
*/
public class WindowsHelperImplTestable extends WindowsHelperImpl {

/**
* The constructor.
*
* @param context the {@link IdeContext}.
*/
public WindowsHelperImplTestable(IdeContext context) {

super(context);
}

@Override
protected List<String> runReg(String... args) {
Comment thread
jakozian marked this conversation as resolved.

// simulate reg.exe filtering: "/f <appName>"
String searchValue = null;
for (int i = 0; i < args.length - 1; i++) {
if ("/f".equalsIgnoreCase(args[i])) {
searchValue = args[i + 1];
break;
}
}
if (!"TestApp".equalsIgnoreCase(searchValue)) {
return List.of();
}
return List.of(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\TestApp",
" DisplayName REG_SZ Test Application",
" DisplayIcon REG_SZ C:\\Program Files\\TestApp\\testapp.exe,0",
" InstallLocation REG_SZ C:\\Program Files\\TestApp",
" UninstallString REG_SZ \"C:\\Program Files\\TestApp\\uninstall.exe\""
);
}
}
64 changes: 64 additions & 0 deletions cli/src/test/java/com/devonfw/tools/ide/os/WindowsHelperMock.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.devonfw.tools.ide.os;

import java.util.List;
import java.util.Properties;

import com.devonfw.tools.ide.context.IdeContext;
Expand All @@ -11,6 +12,18 @@ public class WindowsHelperMock extends WindowsHelperImpl {

private final Properties env;

private static final String MOCK_APP_NAME = "TestApp";

private static final String MOCK_DISPLAY_NAME = "Test Application";

private static final String MOCK_INSTALL_LOCATION = "C:\\Program Files\\TestApp";

private static final String MOCK_DISPLAY_ICON =
"C:\\Program Files\\TestApp\\testapp.exe,0";
private static final String MOCK_UNINSTALL_STRING =
"\"C:\\Program Files\\TestApp\\uninstall.exe\"";


/**
* The constructor.
*/
Expand Down Expand Up @@ -41,6 +54,26 @@ public String getUserEnvironmentValue(String key) {
return this.env.getProperty(key);
}

@Override
public String getDisplayNameFromRegistry(String appName) {
return matchesApp(appName) ? MOCK_DISPLAY_NAME : null;
}

@Override
public String getDisplayIconFromRegistry(String appName) {
return matchesApp(appName) ? MOCK_DISPLAY_ICON : null;
}

@Override
public String getUninstallStringFromRegistry(String appName) {
return matchesApp(appName) ? MOCK_UNINSTALL_STRING : null;
}

@Override
public String getInstallLocationFromRegistry(String appName) {
return matchesApp(appName) ? MOCK_INSTALL_LOCATION : null;
}

@Override
public String getRegistryValue(String path, String key) {

Expand All @@ -51,4 +84,35 @@ public String getRegistryValue(String path, String key) {
}
return null;
}

private boolean matchesApp(String appName) {
return appName != null
&& appName.equalsIgnoreCase(MOCK_APP_NAME);
}

@Override
protected List<String> runReg(String... args) {

// simulate reg.exe filtering: "/f <appName>"
String searchValue = null;
for (int i = 0; i < args.length - 1; i++) {
if ("/f".equalsIgnoreCase(args[i])) {
searchValue = args[i + 1];
break;
}
}

// Only return output if searched app matches
if (!"TestApp".equalsIgnoreCase(searchValue)) {
Comment thread
jakozian marked this conversation as resolved.
Outdated
return List.of(); // same behavior as reg.exe: no results
}

return List.of(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\TestApp",
" DisplayName REG_SZ Test Application",
" DisplayIcon REG_SZ C:\\Program Files\\TestApp\\testapp.exe,0",
" InstallLocation REG_SZ C:\\Program Files\\TestApp",
" UninstallString REG_SZ \"C:\\Program Files\\TestApp\\uninstall.exe\""
);
}
}
Loading