Skip to content
Open
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/*******************************************************************************
* Copyright 2025 Espressif Systems (Shanghai) PTE LTD.
* All rights reserved. Use is subject to license terms.
*******************************************************************************/

package com.espressif.idf.ui.test.executable.cases.project;

import static org.eclipse.swtbot.swt.finder.waits.Conditions.widgetIsEnabled;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;

import org.apache.commons.lang3.SystemUtils;
import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;

import com.espressif.idf.ui.test.common.WorkBenchSWTBot;
import com.espressif.idf.ui.test.common.utility.TestWidgetWaitUtility;
import com.espressif.idf.ui.test.operations.EnvSetupOperations;
import com.espressif.idf.ui.test.operations.ProjectTestOperations;
import com.espressif.idf.ui.test.operations.selectors.LaunchBarConfigSelector;
import com.espressif.idf.ui.test.operations.selectors.LaunchBarTargetSelector;

/**
* Test class to test Debug Process
*
* @author Andrii Filippov
*
*/

@SuppressWarnings("restriction")
@RunWith(SWTBotJunit4ClassRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class IDFProjectDebugProcessTest
{
@BeforeClass
public static void beforeTestClass() throws Exception
{
Fixture.loadEnv();
}

@After
public void afterEachTest()
{
try
{
Fixture.cleanTestEnv();
}
catch (Exception e)
{
System.err.println("Error during cleanup: " + e.getMessage());
}
}

@Test
public void givenNewProjectCreatedWhenFlashedAndDebuggedThenDebuggingWorks() throws Exception
{
if (SystemUtils.IS_OS_LINUX) // temporary solution until new ESP boards arrive for Windows
{
Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Category label typo will break the wizard selection

"EspressIf" should be "Espressif" to match the UI category and avoid widget lookup failures.

-            Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");
+            Fixture.givenNewEspressifIDFProjectIsSelected("Espressif", "Espressif IDF Project");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");
Fixture.givenNewEspressifIDFProjectIsSelected("Espressif", "Espressif IDF Project");
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/IDFProjectDebugProcessTest.java
around line 72, the category label string passed to
Fixture.givenNewEspressifIDFProjectIsSelected is misspelled as "EspressIf";
replace it with the correct UI category "Espressif" so the wizard/widget lookup
matches the UI and selection succeeds.

Fixture.givenProjectNameIs("NewProjecDebugTest");
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo in project name.

There's a spelling error in the project name: "NewProjecDebugTest" should be "NewProjectDebugTest".

Apply this diff to fix the typo:

-Fixture.givenProjectNameIs("NewProjecDebugTest");
+Fixture.givenProjectNameIs("NewProjectDebugTest");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fixture.givenProjectNameIs("NewProjecDebugTest");
Fixture.givenProjectNameIs("NewProjectDebugTest");
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/IDFProjectDebugProcessTest.java
around line 69, the project name string has a typo "NewProjecDebugTest"; update
the string literal to "NewProjectDebugTest" so the fixture uses the correctly
spelled project name.

Fixture.whenNewProjectIsSelected();
Fixture.whenTurnOffOpenSerialMonitorAfterFlashingInLaunchConfig();
Fixture.whenSelectLaunchTargetSerialPort();
Fixture.whenProjectIsBuiltUsingContextMenu();
Fixture.whenFlashProject();
Fixture.thenVerifyFlashDoneSuccessfully();
Fixture.whenSelectDebugConfig();
Fixture.whenSelectLaunchTargetBoard();
// Fixture.whenDebugProject();
// Fixture.whenSwitchPerspective();
// Fixture.checkIfOpenOCDandGDBprocessesArePresent();
// Fixture.whenDebugStoppedUsingContextMenu();
}
else
{
assertTrue(true);
}
}

private static class Fixture
{
private static SWTWorkbenchBot bot;
private static String category;
private static String subCategory;
private static String projectName;

private static void loadEnv() throws Exception
{
bot = WorkBenchSWTBot.getBot();
EnvSetupOperations.setupEspressifEnv(bot);
bot.sleep(1000);
ProjectTestOperations.deleteAllProjects(bot);
}

private static void givenNewEspressifIDFProjectIsSelected(String category, String subCategory)
{
Fixture.category = category;
Fixture.subCategory = subCategory;
}

private static void givenProjectNameIs(String projectName)
{
Fixture.projectName = projectName;
}

private static void whenNewProjectIsSelected() throws Exception
{
ProjectTestOperations.setupProject(projectName, category, subCategory, bot);
}

private static void whenProjectIsBuiltUsingContextMenu() throws IOException
{
ProjectTestOperations.buildProjectUsingContextMenu(projectName, bot);
ProjectTestOperations.waitForProjectBuild(bot);
TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot);
}

private static void whenDebugProject() throws IOException
{
ProjectTestOperations.launchCommandUsingContextMenu(projectName, bot, "Debug Configurations...");
TestWidgetWaitUtility.waitForDialogToAppear(bot, "Debug Configurations", 10000);
bot.tree().getTreeItem("ESP-IDF GDB OpenOCD Debugging").select();
bot.tree().getTreeItem("ESP-IDF GDB OpenOCD Debugging").expand();
bot.tree().getTreeItem("ESP-IDF GDB OpenOCD Debugging").getNode(projectName + " Debug").select();
bot.waitUntil(widgetIsEnabled(bot.button("Debug")), 5000);
bot.button("Debug").click();
}

private static void whenSelectDebugConfig() throws Exception
{
LaunchBarConfigSelector configSelector = new LaunchBarConfigSelector(bot);
configSelector.select(projectName + " Debug");
}

private static void whenSelectLaunchTargetBoard() throws Exception
{
LaunchBarTargetSelector targetSelector = new LaunchBarTargetSelector(bot);
targetSelector.clickEdit();
TestWidgetWaitUtility.waitForDialogToAppear(bot, "New ESP Target", 20000);
SWTBotShell shell = bot.shell("New ESP Target");
bot.comboBoxWithLabel("Board:").setSelection("ESP32-ETHERNET-KIT [usb://1-10]");
TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot);
shell.setFocus();
bot.button("Finish").click();
}

private static void whenSwitchPerspective() throws Exception
{
TestWidgetWaitUtility.waitForDialogToAppear(bot, "Confirm Perspective Switch", 20000);
bot.button("Switch").click();
bot.sleep(10000);
}

private static void whenTurnOffOpenSerialMonitorAfterFlashingInLaunchConfig() throws Exception
{
LaunchBarConfigSelector configSelector = new LaunchBarConfigSelector(bot);
configSelector.clickEdit();
TestWidgetWaitUtility.waitForDialogToAppear(bot, "Edit Configuration", 20000);
bot.cTabItem("Main").show();
bot.cTabItem("Main").setFocus();
SWTBotCheckBox checkBox = bot.checkBox("Open Serial Monitor After Flashing");
if (checkBox.isChecked())
{
checkBox.click();
}
bot.button("OK").click();
}

private static void whenSelectLaunchTargetSerialPort() throws Exception
{
LaunchBarTargetSelector targetSelector = new LaunchBarTargetSelector(bot);
targetSelector.clickEdit();
TestWidgetWaitUtility.waitForDialogToAppear(bot, "New ESP Target", 20000);
SWTBotShell shell = bot.shell("New ESP Target");
bot.comboBoxWithLabel("Serial Port:").setSelection("/dev/ttyUSB1 Dual RS232-HS");
TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot);
shell.setFocus();
bot.button("Finish").click();
}

private static void whenFlashProject() throws IOException
{
ProjectTestOperations.launchCommandUsingContextMenu(projectName, bot, "Run Configurations...");
TestWidgetWaitUtility.waitForDialogToAppear(bot, "Run Configurations", 10000);
bot.tree().getTreeItem("ESP-IDF Application").select();
bot.tree().getTreeItem("ESP-IDF Application").expand();
bot.tree().getTreeItem("ESP-IDF Application").getNode(projectName).select();
bot.waitUntil(widgetIsEnabled(bot.button("Run")), 5000);
bot.button("Run").click();
}

private static void thenVerifyFlashDoneSuccessfully() throws Exception
{
ProjectTestOperations.waitForProjectFlash(bot);
}

private static SWTBotTreeItem fetchProjectFromDebugView()
{
SWTBotView debugView = bot.viewByTitle("Debug");
debugView.show();
debugView.setFocus();
SWTBotTreeItem[] items = debugView.bot().tree().getAllItems();
Optional<SWTBotTreeItem> project = Arrays.asList(items).stream()
.filter(i -> i.getText().equals(projectName + "Debug [ESP-IDF GDB OpenOCD Debugging]")).findFirst();
if (project.isPresent())
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Debug view item match is wrong (missing space before “Debug”)

The code looks for “NameDebug [...]” but the configuration is named “Name Debug”. This will never match.

-                    .filter(i -> i.getText().equals(projectName + "Debug [ESP-IDF GDB OpenOCD Debugging]")).findFirst();
+                    .filter(i -> i.getText().contains(projectName + " Debug")
+                              && i.getText().contains("[ESP-IDF GDB OpenOCD Debugging]"))
+                    .findFirst();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Optional<SWTBotTreeItem> project = Arrays.asList(items).stream()
.filter(i -> i.getText().equals(projectName + "Debug [ESP-IDF GDB OpenOCD Debugging]")).findFirst();
if (project.isPresent())
Optional<SWTBotTreeItem> project = Arrays.asList(items).stream()
.filter(i -> i.getText().contains(projectName + " Debug")
&& i.getText().contains("[ESP-IDF GDB OpenOCD Debugging]"))
.findFirst();
if (project.isPresent())
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/IDFProjectDebugProcessTest.java
around lines 216-218, the filter checks for projectName + "Debug [ESP-IDF GDB
OpenOCD Debugging]" which is missing a space and will never match the actual
item label; update the match to include the space (projectName + " Debug
[ESP-IDF GDB OpenOCD Debugging]") or alternatively use a more robust check such
as contains or startsWith with the projectName and "Debug" to avoid exact
spacing issues.

{
return project.get();
}

return null;
}

private static boolean checkifOpenOCDandGDBprocessesArePresent()
{
SWTBotTreeItem projectItem = fetchProjectFromDebugView();
if (projectItem != null)
{
projectItem.select();

boolean openOCDexe = ProjectTestOperations.isFileAbsent(projectItem, "openocd.exe");
boolean GDBexe = ProjectTestOperations.isFileAbsent(projectItem, "riscv32-esp-elf-gdb.exe");
if (openOCDexe || GDBexe)
{
return false;
}
return true;
}
return false;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Process presence check uses Windows “.exe” on a Linux‑only path and inverted logic

On Linux there’s no “.exe”. Also, using isFileAbsent and then negating only at the end obscures intent.

-                boolean openOCDexe = ProjectTestOperations.isFileAbsent(projectItem, "openocd.exe");
-                boolean GDBexe = ProjectTestOperations.isFileAbsent(projectItem, "riscv32-esp-elf-gdb.exe");
-                if (openOCDexe || GDBexe)
-                {
-                    return false;
-                }
-                return true;
+                final String openocdName = SystemUtils.IS_OS_WINDOWS ? "openocd.exe" : "openocd";
+                // Support both Xtensa and RISC‑V toolchains
+                final String[] gdbCandidates = SystemUtils.IS_OS_WINDOWS
+                        ? new String[] {"xtensa-esp32-elf-gdb.exe", "xtensa-esp32s2-elf-gdb.exe",
+                                        "xtensa-esp32s3-elf-gdb.exe", "riscv32-esp-elf-gdb.exe"}
+                        : new String[] {"xtensa-esp32-elf-gdb", "xtensa-esp32s2-elf-gdb",
+                                        "xtensa-esp32s3-elf-gdb", "riscv32-esp-elf-gdb"};
+
+                boolean openocdPresent = !ProjectTestOperations.isFileAbsent(projectItem, openocdName);
+                boolean gdbPresent = false;
+                for (String gdb : gdbCandidates) {
+                    if (!ProjectTestOperations.isFileAbsent(projectItem, gdb)) {
+                        gdbPresent = true;
+                        break;
+                    }
+                }
+                return openocdPresent && gdbPresent;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static boolean checkifOpenOCDandGDBprocessesArePresent()
{
SWTBotTreeItem projectItem = fetchProjectFromDebugView();
if (projectItem != null)
{
projectItem.select();
boolean openOCDexe = ProjectTestOperations.isFileAbsent(projectItem, "openocd.exe");
boolean GDBexe = ProjectTestOperations.isFileAbsent(projectItem, "riscv32-esp-elf-gdb.exe");
if (openOCDexe || GDBexe)
{
return false;
}
return true;
}
return false;
private static boolean checkifOpenOCDandGDBprocessesArePresent()
{
SWTBotTreeItem projectItem = fetchProjectFromDebugView();
if (projectItem != null)
{
projectItem.select();
final String openocdName = SystemUtils.IS_OS_WINDOWS ? "openocd.exe" : "openocd";
// Support both Xtensa and RISC-V toolchains
final String[] gdbCandidates = SystemUtils.IS_OS_WINDOWS
? new String[] {"xtensa-esp32-elf-gdb.exe", "xtensa-esp32s2-elf-gdb.exe",
"xtensa-esp32s3-elf-gdb.exe", "riscv32-esp-elf-gdb.exe"}
: new String[] {"xtensa-esp32-elf-gdb", "xtensa-esp32s2-elf-gdb",
"xtensa-esp32s3-elf-gdb", "riscv32-esp-elf-gdb"};
boolean openocdPresent = !ProjectTestOperations.isFileAbsent(projectItem, openocdName);
boolean gdbPresent = false;
for (String gdb : gdbCandidates) {
if (!ProjectTestOperations.isFileAbsent(projectItem, gdb)) {
gdbPresent = true;
break;
}
}
return openocdPresent && gdbPresent;
}
return false;
}
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/IDFProjectDebugProcessTest.java
around lines 226 to 241, the process presence check incorrectly looks for
Windows “.exe” filenames on a Linux-only path and uses inverted/obscured logic
by calling isFileAbsent then negating at the end; change the checks to use the
Linux binary names (remove “.exe”, e.g. "openocd" and "riscv32-esp-elf-gdb") and
simplify logic so you directly test presence (either call an isFilePresent
method or immediately return false if isFileAbsent(...) is true), returning true
only when both binaries are found. Ensure the method returns false early if
either file is missing and true otherwise.

}

private static void checkIfOpenOCDandGDBprocessesArePresent() throws IOException
{
assertTrue("Debug process was not successfully started", checkifOpenOCDandGDBprocessesArePresent());
}

private static void whenDebugStoppedUsingContextMenu() throws IOException
{
ProjectTestOperations.launchCommandUsingContextMenu(projectName + "Debug [ESP-IDF GDB OpenOCD Debugging]",
bot, "Terminate/Disconnect All");
bot.sleep(10000);
ProjectTestOperations.findInConsole(bot, "IDF Process Console", "dropped 'gdb'");
TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Terminate via Debug view, not Project Explorer context

The helper launches a Project Explorer context menu, which won’t target the active debug session. Use the Debug view’s toolbar or context menu on the session node.

-            ProjectTestOperations.launchCommandUsingContextMenu(projectName + "Debug [ESP-IDF GDB OpenOCD Debugging]",
-                    bot, "Terminate/Disconnect All");
-            bot.sleep(10000);
-            ProjectTestOperations.findInConsole(bot, "IDF Process Console", "dropped 'gdb'");
+            SWTBotView debugView = bot.viewByTitle("Debug");
+            debugView.show();
+            debugView.setFocus();
+            SWTBotTreeItem item = fetchProjectFromDebugView();
+            if (item != null) {
+                item.select();
+                // Prefer toolbar; fallback to context menu label if needed
+                try {
+                    debugView.toolbarButton("Terminate").click();
+                } catch (Exception e) {
+                    item.contextMenu("Terminate/Disconnect All").click();
+                }
+                ProjectTestOperations.findInConsole(bot, "IDF Process Console", "dropped 'gdb'");
+            }
             TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/IDFProjectDebugProcessTest.java
around lines 249-256, the test currently uses Project Explorer context menu
which doesn't target the active debug session; instead open the Debug view,
locate the running debug session node matching projectName + "Debug [ESP-IDF GDB
OpenOCD Debugging]" and invoke the "Terminate/Disconnect All" action via the
Debug view toolbar or the session node's context menu; keep the subsequent
bot.sleep, console check for "dropped 'gdb'", and wait-for-operations sync but
replace the ProjectTestOperations.launchCommandUsingContextMenu call with a
Debug-view-specific action (or add a helper that selects the Debug view, finds
the session node, and triggers the terminate action).


private static void cleanTestEnv()
{
TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot);
ProjectTestOperations.closeAllProjects(bot);
ProjectTestOperations.deleteAllProjects(bot);
}
}
}
Loading