Skip to content

Commit

Permalink
Merge pull request #72 from AnetteTaivere/master
Browse files Browse the repository at this point in the history
Add functional tests
  • Loading branch information
karoliineh authored Jun 26, 2024
2 parents e8d7775 + 986be03 commit 4c2b625
Show file tree
Hide file tree
Showing 49 changed files with 2,439 additions and 740 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: coverage

on:
pull_request:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
cache: maven

- name: Set up Node.js 18
uses: actions/setup-node@v3
with:
node-version: '18.x'

- name: Build with Maven
run: mvn install

- name: Create Jacoco report
run: mvn test jacoco:report

- name: Coveralls
uses: coverallsapp/[email protected]
with:
base-path: src/main/java
file: target/site/jacoco/jacoco.xml
95 changes: 95 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,54 @@
<version>0.0.4-SNAPSHOT</version>
<dependencies>

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.14</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/io.github.hakky54/logcaptor -->
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>logcaptor</artifactId>
<version>2.9.2</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/uk.org.webcompere/system-stubs-jupiter -->
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-jupiter</artifactId>
<version>2.1.6</version>
<scope>test</scope>
</dependency>

<!-- lsp4j DAP -->
<dependency>
<groupId>org.eclipse.lsp4j</groupId>
Expand Down Expand Up @@ -132,6 +180,53 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<consoleOutputReporter>
<disable>true</disable>
</consoleOutputReporter>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
</dependency>
</dependencies>
</plugin>

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<configuration>
<excludes>
<exclude>**/abstractdebugging/*</exclude>
<exclude>**/HTTPserver/*</exclude>
<exclude>**/api/jsonrpc/*</exclude>
<exclude>**/magpiebridge/*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4 changes: 2 additions & 2 deletions src/main/java/HTTPserver/GobPieHttpHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ private String getCFG(String funName) {
try {
String cfg;
if (funName.equals("<arg>")) {
cfg = goblintService.arg_dot().get().getArg();
cfg = goblintService.arg_dot().get().arg();
} else {
cfg = goblintService.cfg_dot(params).get().getCfg();
cfg = goblintService.cfg_dot(params).get().cfg();
}
return cfg2svg(cfg);
} catch (ExecutionException | InterruptedException e) {
Expand Down
29 changes: 22 additions & 7 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@
import abstractdebugging.AbstractDebuggingServerLauncher;
import abstractdebugging.ResultsService;
import analysis.GoblintAnalysis;
import analysis.ShowCFGCommand;
import api.GoblintService;
import api.GoblintServiceLauncher;
import api.messages.params.Params;
import goblintserver.GoblintConfWatcher;
import goblintserver.GoblintServer;
import gobpie.GobPieConfReader;
import gobpie.GobPieConfiguration;
import gobpie.GobPieException;
import magpiebridge.GoblintLanguageExtensionHandler;
import magpiebridge.GoblintMagpieServer;
import magpiebridge.GoblintServerConfiguration;
import magpiebridge.ShowCFGCommand;
import magpiebridge.core.MagpieServer;
import magpiebridge.core.ServerAnalysis;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import util.FileWatcher;

import java.io.File;
import java.nio.file.Path;

public class Main {

Expand All @@ -40,14 +47,17 @@ public static void main(String... args) {
// Connect GoblintService and read configuration
GoblintService goblintService = connectGoblintService(magpieServer, gobpieConfiguration, goblintServer);

// Create file watcher for Goblint configuration
GoblintConfWatcher goblintConfWatcher = getGoblintConfWatcher(magpieServer, goblintService, gobpieConfiguration);

// Add analysis
addAnalysis(magpieServer, gobpieConfiguration, goblintServer, goblintService);
addAnalysis(magpieServer, gobpieConfiguration, goblintServer, goblintService, goblintConfWatcher);

// Launch magpieServer
magpieServer.configurationDone();
log.info("MagpieBridge server launched.");

if (args.length > 0 && gobpieConfiguration.enableAbstractDebugging()) {
if (args.length > 0 && gobpieConfiguration.abstractDebugging()) {
// Launch abstract debugging server
String socketAddress = args[0];
launchAbstractDebuggingServer(socketAddress, goblintService);
Expand Down Expand Up @@ -90,7 +100,7 @@ private static GoblintMagpieServer createMagpieServer() {
*
* @throws GobPieException if running the server start command fails
*/
private static GoblintServer startGoblintServer(MagpieServer magpieServer, GobPieConfiguration gobpieConfiguration) {
public static GoblintServer startGoblintServer(MagpieServer magpieServer, GobPieConfiguration gobpieConfiguration) {
GoblintServer goblintServer = new GoblintServer(magpieServer, gobpieConfiguration);
if (log.isDebugEnabled()) {
log.debug("Goblint version info:\n" + goblintServer.checkGoblintVersion());
Expand All @@ -111,7 +121,7 @@ private static GoblintService connectGoblintService(MagpieServer magpieServer, G
GoblintService goblintService = launcher.connect(goblintServer.getGoblintSocket());

// Read Goblint configurations
goblintService.read_config(new Params(new File(gobpieConfiguration.getGoblintConf()).getAbsolutePath()))
goblintService.read_config(new Params(new File(gobpieConfiguration.goblintConf()).getAbsolutePath()))
.exceptionally(ex -> {
String msg = "Goblint was unable to successfully read the configuration: " + ex.getMessage();
magpieServer.forwardMessageToClient(new MessageParams(MessageType.Warning, msg));
Expand All @@ -123,19 +133,24 @@ private static GoblintService connectGoblintService(MagpieServer magpieServer, G
return goblintService;
}

private static GoblintConfWatcher getGoblintConfWatcher(GoblintMagpieServer magpieServer, GoblintService goblintService, GobPieConfiguration gobpieConfiguration) {
FileWatcher fileWatcher = new FileWatcher(Path.of(gobpieConfiguration.goblintConf()));
return new GoblintConfWatcher(magpieServer, goblintService, gobpieConfiguration, fileWatcher);
}


/**
* Method for creating and adding Goblint analysis to MagpieBridge server.
* <p>
* Creates the GoblintAnalysis classes.
*/
private static void addAnalysis(MagpieServer magpieServer, GobPieConfiguration gobpieConfiguration,
GoblintServer goblintServer, GoblintService goblintService) {
GoblintServer goblintServer, GoblintService goblintService, GoblintConfWatcher goblintConfWatcher) {
// define language
String language = "c";

// add analysis to the MagpieServer
ServerAnalysis serverAnalysis = new GoblintAnalysis(magpieServer, goblintServer, goblintService, gobpieConfiguration);
ServerAnalysis serverAnalysis = new GoblintAnalysis(magpieServer, goblintServer, goblintService, gobpieConfiguration, goblintConfWatcher);
magpieServer.addAnalysis(Either.forLeft(serverAnalysis), language);

// add HTTP server for showing CFGs, only if the option is specified in the configuration
Expand Down
54 changes: 27 additions & 27 deletions src/main/java/abstractdebugging/AbstractDebuggingServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public CompletableFuture<SetBreakpointsResponse> setBreakpoints(SetBreakpointsAr
continue;
}

var targetLocation = new GoblintLocation(goblintSourcePath, breakpoint.getLine(), breakpoint.getColumn() == null ? 0 : breakpoint.getColumn());
var targetLocation = new GoblintLocation(goblintSourcePath, breakpoint.getLine(), breakpoint.getColumn() == null ? 0 : breakpoint.getColumn(), null, null);
CFGNodeInfo cfgNode;
try {
cfgNode = resultsService.lookupCFGNode(targetLocation);
Expand All @@ -152,8 +152,8 @@ public CompletableFuture<SetBreakpointsResponse> setBreakpoints(SetBreakpointsAr
continue;
}
breakpointStatus.setSource(args.getSource());
breakpointStatus.setLine(cfgNode.location().getLine());
breakpointStatus.setColumn(cfgNode.location().getColumn());
breakpointStatus.setLine(cfgNode.location().line());
breakpointStatus.setColumn(cfgNode.location().column());

ConditionalExpression condition;
if (breakpoint.getCondition() == null) {
Expand Down Expand Up @@ -193,11 +193,11 @@ public CompletableFuture<SetBreakpointsResponse> setBreakpoints(SetBreakpointsAr

int startIndex;
for (startIndex = 0; startIndex < breakpoints.size(); startIndex++) {
if (breakpoints.get(startIndex).cfgNode().location().getFile().equals(goblintSourcePath)) {
if (breakpoints.get(startIndex).cfgNode().location().file().equals(goblintSourcePath)) {
break;
}
}
breakpoints.removeIf(b -> b.cfgNode().location().getFile().equals(goblintSourcePath));
breakpoints.removeIf(b -> b.cfgNode().location().file().equals(goblintSourcePath));
breakpoints.addAll(startIndex, newBreakpoints);

var response = new SetBreakpointsResponse();
Expand Down Expand Up @@ -428,10 +428,10 @@ private StepInTarget target(int id, String label, GoblintLocation location) {
var target = new StepInTarget();
target.setId(id);
target.setLabel(label);
target.setLine(location.getLine());
target.setColumn(location.getColumn());
target.setEndLine(location.getEndLine());
target.setEndColumn(location.getEndColumn());
target.setLine(location.line());
target.setColumn(location.column());
target.setEndLine(location.endLine());
target.setEndColumn(location.endColumn());
return target;
}

Expand Down Expand Up @@ -713,7 +713,7 @@ private void runToNextBreakpoint(int direction) {
String stopReason;
GoblintLocation targetLocation;
List<NodeInfo> targetNodes;
if (breakpoints.size() == 0) {
if (breakpoints.isEmpty()) {
stopReason = "entry";
targetLocation = null;
targetNodes = resultsService.lookupNodes(LookupParams.entryPoint());
Expand Down Expand Up @@ -975,13 +975,13 @@ public CompletableFuture<StackTraceResponse> stackTrace(StackTraceArguments args
if (frame.getNode() != null) {
stackFrame.setName((frame.isAmbiguousFrame() ? "? " : "") + (frame.getLocalThreadIndex() != currentThreadId ? "^" : "") + frame.getNode().function() + " " + frame.getNode().nodeId());
var location = frame.getNode().location();
stackFrame.setLine(location.getLine());
stackFrame.setColumn(location.getColumn());
stackFrame.setEndLine(location.getEndLine());
stackFrame.setEndColumn(location.getEndColumn());
stackFrame.setLine(location.line());
stackFrame.setColumn(location.column());
stackFrame.setEndLine(location.endLine());
stackFrame.setEndColumn(location.endColumn());
var source = new Source();
source.setName(location.getFile());
source.setPath(new File(location.getFile()).getAbsolutePath());
source.setName(location.file());
source.setPath(new File(location.file()).getAbsolutePath());
stackFrame.setSource(source);
} else {
stackFrame.setName("No matching path");
Expand Down Expand Up @@ -1011,8 +1011,8 @@ public CompletableFuture<ScopesResponse> scopes(ScopesArguments args) {
JsonObject state = resultsService.lookupState(currentNode.nodeId());
JsonElement globalState = resultsService.lookupGlobalState();
Map<String, GoblintVarinfo> varinfos = resultsService.getVarinfos().stream()
.filter(v -> (v.getFunction() == null || v.getFunction().equals(currentNode.function())) && !"function".equals(v.getRole()))
.collect(Collectors.toMap(GoblintVarinfo::getName, v -> v));
.filter(v -> (v.function() == null || v.function().equals(currentNode.function())) && !"function".equals(v.role()))
.collect(Collectors.toMap(GoblintVarinfo::name, v -> v));

List<Variable> localVariables = new ArrayList<>();
List<Variable> globalVariables = new ArrayList<>();
Expand Down Expand Up @@ -1043,29 +1043,29 @@ public CompletableFuture<ScopesResponse> scopes(ScopesArguments args) {

// Add variables.
for (var varinfo : varinfos.values()) {
if (varinfo.getOriginalName() == null || (varinfo.getFunction() == null && STD_VARIABLES.contains(varinfo.getOriginalName()))) {
if (varinfo.original_name() == null || (varinfo.function() == null && STD_VARIABLES.contains(varinfo.original_name()))) {
// Hide synthetic variables because they are impossible to interpret without looking at the CFG.
// Hide global built-in and standard library variables because they are generally irrelevant and not used in the analysis.
continue;
}

String name = varinfo.getName().equals(varinfo.getOriginalName())
? varinfo.getName()
: varinfo.getOriginalName() + " (" + varinfo.getName() + ")";
JsonElement value = domainValues.get(varinfo.getName());
String name = varinfo.name().equals(varinfo.original_name())
? varinfo.name()
: varinfo.original_name() + " (" + varinfo.name() + ")";
JsonElement value = domainValues.get(varinfo.name());
if (value == null) {
if (varinfo.getFunction() != null) {
if (varinfo.function() != null) {
// Skip local variables that are not present in base domain, because this generally means we are on a special ARG node where local variables are not tracked.
continue;
}
// If domain does not contain variable value use Goblint to evaluate the value.
// This generally happens for global variables in multithreaded mode.
value = resultsService.evaluateExpression(currentNode.nodeId(), varinfo.getName());
value = resultsService.evaluateExpression(currentNode.nodeId(), varinfo.name());
}

List<Variable> scope = varinfo.getFunction() == null ? globalVariables : localVariables;
List<Variable> scope = varinfo.function() == null ? globalVariables : localVariables;

scope.add(domainValueToVariable(name, varinfo.getType(), value));
scope.add(domainValueToVariable(name, varinfo.type(), value));
}

List<Variable> rawVariables = new ArrayList<>();
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/abstractdebugging/ResultsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public List<NodeInfo> lookupNodes(LookupParams params) {
// That looks strange, so we patch it to be only the end of the last line of the function.
// TODO: Maybe it would be better to adjust location when returning stack so the node info retains the original location
return nodeInfo.withLocation(new GoblintLocation(
nodeInfo.location().getFile(),
nodeInfo.location().getEndLine(), nodeInfo.location().getEndColumn(),
nodeInfo.location().getEndLine(), nodeInfo.location().getEndColumn()
nodeInfo.location().file(),
nodeInfo.location().endLine(), nodeInfo.location().endColumn(),
nodeInfo.location().endLine(), nodeInfo.location().endColumn()
));
} else {
return nodeInfo;
Expand Down
Loading

0 comments on commit 4c2b625

Please sign in to comment.