Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions checkmarx-ast-eclipse-plugin-tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Bundle-SymbolicName: com.checkmarx.ast.eclipse.tests
Bundle-Version: 1.0.0.qualifier
Fragment-Host: com.checkmarx.eclipse.plugin;bundle-version="1.0.0"
Require-Bundle:
com.checkmarx.eclipse.devassist,
org.eclipse.swtbot.swt.finder,
org.eclipse.swtbot.eclipse.finder,
org.eclipse.swtbot.junit5_x,
Expand All @@ -15,4 +16,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ClassPath: .,lib/mockito-core-5.14.2.jar,lib/powermock-core-*.jar, lib/byte-buddy-1.17.8.jar, lib/byte-buddy-agent-1.17.8.jar
Automatic-Module-Name: com.checkmarx.ast.eclipse.tests
Import-Package: com.checkmarx.eclipse.common.runner,
com.fasterxml.jackson.annotation,
com.fasterxml.jackson.core,
com.fasterxml.jackson.databind,
org.slf4j;version="[2.0.0,3.0.0)"
11 changes: 10 additions & 1 deletion checkmarx-ast-eclipse-plugin-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<test.includes>
**/Test*.java,**/*Test.java,**/*Tests.java,**/*TestCase.java</test.includes>
**/unit/**/Test*.java,**/unit/**/*Test.java,**/unit/**/*Tests.java,**/unit/**/*TestCase.java
</test.includes>
<test.excludes>
**/ui/**/*Test.java,**/integration/**/*Test.java,**/it/**/*Test.java
</test.excludes>
</properties>
<groupId>com.checkmarx.ast.eclipse.tests</groupId>
<artifactId>com.checkmarx.ast.eclipse.tests</artifactId>
Expand Down Expand Up @@ -40,9 +44,11 @@
<goal>report</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/site/jacoco-aggregate</outputDirectory>
<formats>
<format>XML</format>
<format>CSV</format>
<format>HTML</format>
</formats>
</configuration>
</execution>
Expand All @@ -61,6 +67,9 @@
<includes>
<include>${test.includes}</include>
</includes>
<excludes>
<exclude>${test.excludes}</exclude>
</excludes>
</configuration>
</plugin>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package checkmarx.ast.eclipse.plugin.tests.unit.devassist.backend;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.checkmarx.eclipse.devassist.backend.DevAssistScanStateHolder;

class DevAssistScanStateHolderTest {

private DevAssistScanStateHolder holder;

@BeforeEach
void setUp() {
holder = new DevAssistScanStateHolder();
}

@Test
void getStateHash_unknownPath_returnsNull() {
assertNull(holder.getStateHash("/unknown/path.java"));
}

@Test
void updateStateHash_thenGetStateHash_returnsUpdatedValue() {
holder.updateStateHash("/path/file.java", 12345L);
assertEquals(12345L, holder.getStateHash("/path/file.java"));
}

@Test
void updateStateHash_overwritesExistingValue() {
holder.updateStateHash("/path/file.java", 100L);
holder.updateStateHash("/path/file.java", 200L);
assertEquals(200L, holder.getStateHash("/path/file.java"));
}

@Test
void updateStateHash_multiplePaths_tracksEachIndependently() {
holder.updateStateHash("/a.java", 1L);
holder.updateStateHash("/b.java", 2L);
assertEquals(1L, holder.getStateHash("/a.java"));
assertEquals(2L, holder.getStateHash("/b.java"));
}

@Test
void hasChanged_unknownPath_returnsTrue() {
assertTrue(holder.hasChanged("/new/path.java", 12345L));
}

@Test
void hasChanged_unchangedFile_returnsFalse() {
long hash = 99999L;
holder.updateStateHash("/path/file.java", hash);
assertFalse(holder.hasChanged("/path/file.java", hash));
}

@Test
void hasChanged_changedFile_returnsTrue() {
holder.updateStateHash("/path/file.java", 100L);
assertTrue(holder.hasChanged("/path/file.java", 200L));
}

@Test
void hasChanged_nullPath_returnsTrue() {
assertTrue(holder.hasChanged(null, 12345L));
}

@Test
void markScanComplete_removesInFlightMarker() {
holder.updateStateHash("/path/file.java", 100L);
assertTrue(holder.hasChanged("/path/file.java", 200L));
holder.markScanComplete("/path/file.java");
// After marking complete, another change should be detected
assertTrue(holder.hasChanged("/path/file.java", 300L));
}

@Test
void clearFileState_removesFileState() {
holder.updateStateHash("/path/file.java", 12345L);
assertEquals(12345L, holder.getStateHash("/path/file.java"));
holder.clearFileState("/path/file.java");
assertNull(holder.getStateHash("/path/file.java"));
}

@Test
void clearAll_removesAllState() {
holder.updateStateHash("/a.java", 1L);
holder.updateStateHash("/b.java", 2L);
holder.clearAll();
assertNull(holder.getStateHash("/a.java"));
assertNull(holder.getStateHash("/b.java"));
}

@Test
void getStatistics_returnsTrackedFileCount() {
holder.updateStateHash("/a.java", 1L);
holder.updateStateHash("/b.java", 2L);
String stats = holder.getStatistics();
assertNotNull(stats);
assertTrue(stats.contains("2") || stats.contains("Tracked files"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package checkmarx.ast.eclipse.plugin.tests.unit.devassist.backend;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import com.checkmarx.eclipse.devassist.backend.GlobalScannerController;
import com.checkmarx.eclipse.devassist.backend.GlobalScannerController.ScannerStateListener;
import com.checkmarx.eclipse.devassist.backend.ScannerRegistry;
import com.checkmarx.eclipse.devassist.backend.ScannerRegistry.ScannerType;

/**
* Unit tests for {@link GlobalScannerController}. It is a JVM-wide singleton,
* so every test resets its internal state map/listener list via reflection
* in {@code @BeforeEach} to avoid bleeding state across tests (and across
* other test classes in this module, e.g. {@code ScannerFactoryTest}, that
* also go through {@code getInstance()}).
*/
class GlobalScannerControllerTest {

private GlobalScannerController controller;

@BeforeEach
@SuppressWarnings("unchecked")
void resetSingletonState() throws Exception {
controller = GlobalScannerController.getInstance();

Field stateField = GlobalScannerController.class.getDeclaredField("scannerState");
stateField.setAccessible(true);
((Map<ScannerType, Boolean>) stateField.get(controller)).clear();

Field listenersField = GlobalScannerController.class.getDeclaredField("stateListeners");
listenersField.setAccessible(true);
((List<ScannerStateListener>) listenersField.get(controller)).clear();
}

@Test
@DisplayName("isScannerEnabled defaults to true for a type that was never explicitly set")
void isScannerEnabledDefaultsToTrue() {
assertTrue(controller.isScannerEnabled(ScannerType.OSS));
}

@Test
@DisplayName("isScannerEnabled returns false for a null type")
void isScannerEnabledHandlesNullType() {
assertFalse(controller.isScannerEnabled(null));
}

@Test
@DisplayName("disableScanner then isScannerEnabled reflects the disabled state")
void disableScannerThenIsScannerEnabled() {
controller.disableScanner(ScannerType.SECRETS);
assertFalse(controller.isScannerEnabled(ScannerType.SECRETS));

controller.enableScanner(ScannerType.SECRETS);
assertTrue(controller.isScannerEnabled(ScannerType.SECRETS));
}

@Test
@DisplayName("enableScanner/disableScanner with a null type is a safe no-op")
void enableDisableHandleNullType() {
controller.enableScanner(null);
controller.disableScanner(null);
// No exception, and no scanner type is affected.
assertEquals(ScannerType.values().length, controller.getEnabledScannerCount());
}

@Test
@DisplayName("disableAllScanners then enableAllScanners toggles every scanner type")
void disableThenEnableAllScanners() {
controller.disableAllScanners();
assertEquals(0, controller.getEnabledScannerCount());
for (ScannerType type : ScannerType.values()) {
assertFalse(controller.isScannerEnabled(type));
}

controller.enableAllScanners();
assertEquals(ScannerType.values().length, controller.getEnabledScannerCount());
}

@Test
@DisplayName("Listener is notified only on an actual state transition, not on a redundant call")
void listenerNotifiedOnlyOnRealTransition() {
// Note: wasEnabled/wasDisabled are computed from the map's PREVIOUS explicit
// value, not from isScannerEnabled()'s default-true fallback - so after the
// @BeforeEach map .clear(), the type has no explicit entry yet. Prime one
// with an explicit enableScanner() call (itself not guaranteed to notify)
// before attaching the listener, so the subsequent disable really is a
// transition from a known "true" state.
controller.enableScanner(ScannerType.IAC);
List<Boolean> notifications = new ArrayList<>();
ScannerStateListener listener = (type, enabled) -> notifications.add(enabled);
controller.addScannerStateListener(listener);

controller.disableScanner(ScannerType.IAC);
controller.disableScanner(ScannerType.IAC);
controller.enableScanner(ScannerType.IAC);
controller.enableScanner(ScannerType.IAC);

assertEquals(List.of(false, true), notifications);
}

@Test
@DisplayName("removeScannerStateListener stops further notifications")
void removeScannerStateListenerStopsNotifications() {
controller.enableScanner(ScannerType.ASCA);
List<Boolean> notifications = new ArrayList<>();
ScannerStateListener listener = (type, enabled) -> notifications.add(enabled);
controller.addScannerStateListener(listener);
controller.removeScannerStateListener(listener);

controller.disableScanner(ScannerType.ASCA);

assertTrue(notifications.isEmpty());
}

@Test
@DisplayName("A listener that throws does not prevent other listeners from being notified")
void listenerExceptionDoesNotBlockOtherListeners() {
controller.enableScanner(ScannerType.CONTAINERS);
List<Boolean> notifications = new ArrayList<>();
controller.addScannerStateListener((type, enabled) -> {
throw new RuntimeException("boom");
});
controller.addScannerStateListener((type, enabled) -> notifications.add(enabled));

controller.disableScanner(ScannerType.CONTAINERS);

assertEquals(List.of(false), notifications);
}

@Test
@DisplayName("getStateReport lists every scanner type with its enabled/disabled state")
void getStateReportListsAllTypes() {
controller.disableScanner(ScannerType.OSS);

String report = controller.getStateReport();

assertTrue(report.contains("DISABLED"));
assertTrue(report.contains("ENABLED"));
for (ScannerType type : ScannerType.values()) {
assertTrue(report.contains(type.getDisplayName()));
}
}
}
Loading
Loading