Skip to content
Merged
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
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Java CI with Maven

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven # Optional: Caches Maven dependencies

- name: Build with Maven
run: mvn -B package --file pom.xml

- name: Upload JAR artifact
uses: actions/upload-artifact@v4
with:
name: stardust-jar
path: target/stardust-0.0.1.jar
if-no-files-found: error
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,40 @@ STARDUST is a framework for spectrum-based fault localization (SBFL).
The framework was used to conduct experiments with SBFL during my bachelor thesis.


## Requirements

This project requires Java 17 or newer to build and run.


## Installation

STARDUST uses [maven](https://maven.apache.org/) as its build tool.
The `pom.xml` file contains all dependencies you need in order to run the framework.

Comment on lines 12 to 16
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Please add instructions on how to use the published artifact from Github

### Using the Published Artifact

Successful builds on the `main` or `master` branch publish a JAR artifact named `stardust-jar`. You can download this artifact by following these steps:

1. Navigate to the **Actions** tab of the GitHub repository.
2. Select the **Java CI with Maven** workflow from the list of workflows.
3. Choose a successful run (usually marked with a green checkmark).
4. Scroll down to the **Artifacts** section at the bottom of the run page.
5. Download the `stardust-jar` artifact. This will typically be a ZIP file containing `stardust-0.0.1.jar`.

Once downloaded and unzipped, you can run specific functionalities using a command similar to this:

```bash
java -cp stardust-0.0.1.jar fk.stardust.evaluation.sbfl.CreateRankings [args]
```
(Replace `[args]` with any arguments required by the chosen main class.)


## Build Status

![Build Status](https://github.com/FaKeller/stardust/actions/workflows/ci.yml/badge.svg)

This project uses GitHub Actions to automatically run tests and build the project upon commits and pull requests, ensuring code quality and integration.


## Theoretical Background

Expand Down
35 changes: 17 additions & 18 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,30 @@

<!-- library dependencies -->
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6.1</version>
</dependency>

<!-- weka machine learning -->
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-dev</artifactId>
<version>3.7.10</version>
<artifactId>weka-stable</artifactId>
<version>3.8.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>LibSVM</artifactId>
<version>1.0.5</version>
<groupId>tw.edu.ntu.csie</groupId>
<artifactId>libsvm</artifactId>
<version>3.30</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-dev</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- QA dependencies -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.5</version>
<version>7.7.1</version>
<scope>test</scope>
</dependency>
<!-- <dependency>
Expand Down Expand Up @@ -127,7 +121,12 @@
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
<version>3.1.2</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
Expand All @@ -140,8 +139,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>17</source>
<target>17</target>

<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import fk.stardust.evaluation.IExperiment;
import fk.stardust.localizer.Ranking;
Expand Down Expand Up @@ -147,8 +147,8 @@ public void conduct() throws Exception {
}

System.out.println(String.format("Wasted Effort: %d", maxWastedEffort));
System.out.println(String.format("Percentage examined: %f", new Double(maxWastedEffort * 100)
/ new Double(s.getNodes().size())));
System.out.println(String.format("Percentage examined: %f", (double) (maxWastedEffort * 100)
/ (double) (s.getNodes().size())));
System.out.println(String.format("Last examined node: %s", lastExaminedNode.toString()));
}

Expand Down Expand Up @@ -211,20 +211,19 @@ private String getFileExtension(final File file) {
private Set<INode<String>> getRealFaultLocations(final ISpectra<String> spectra) throws JDOMException, IOException {
final Set<INode<String>> locations = new HashSet<>();
final String repository = this.root.getAbsolutePath() + "/repository.xml";
final Document doc = new SAXBuilder().build(repository);
final SAXBuilder saxBuilder = new SAXBuilder();
final Document doc = saxBuilder.build(repository);

// loop over all packages of the trace file
for (final Object bugObject : doc.getRootElement().getChildren()) {
final Element bug = (Element) bugObject;
for (final Element bug : doc.getRootElement().getChildren()) {

// skip irrelevant bugs
if (this.bugId != Integer.parseInt(bug.getAttributeValue("id"))) {
continue;
}

// get files
for (final Object fileObject : bug.getChild("fixedFiles").getChildren()) {
final Element file = (Element) fileObject;
for (final Element file : bug.getChild("fixedFiles").getChildren()) {
final String filename = file.getAttributeValue("name");
final String extension = filename.substring(filename.length() - 5);
if (extension.compareTo(".java") != 0 || filename.toLowerCase().indexOf("test") != -1) {
Expand Down
22 changes: 10 additions & 12 deletions src/main/java/fk/stardust/evaluation/ibugs/IBugsFaultLocations.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import fk.stardust.provider.CoberturaProvider;
import fk.stardust.traces.INode;
Expand Down Expand Up @@ -79,11 +79,11 @@ public IBugsFaultLocations(final java.io.File file) throws JDOMException, IOExce
* @throws JDOMException
*/
private void parse(final java.io.File faultLocationFile) throws JDOMException, IOException {
final Document doc = new SAXBuilder().build(faultLocationFile);
final SAXBuilder saxBuilder = new SAXBuilder();
final Document doc = saxBuilder.build(faultLocationFile);

// loop over all bugs of the real fault locations file
for (final Object bugObject : doc.getRootElement().getChildren()) {
final Element bug = (Element) bugObject;
for (final Element bug : doc.getRootElement().getChildren()) {

// create bug object
Bug curBug;
Expand All @@ -98,9 +98,8 @@ private void parse(final java.io.File faultLocationFile) throws JDOMException, I


// get files
for (final Object fileObject : bug.getChildren()) {
final Element file = (Element) fileObject;
final String filename = file.getAttributeValue("name");
for (final Element fileElement : bug.getChildren()) {
final String filename = fileElement.getAttributeValue("name");

// ensure we have java extension and no test sources
if (filename == null || FileUtils.getFileExtension(filename).compareTo("java") != 0
Expand All @@ -114,8 +113,7 @@ private void parse(final java.io.File faultLocationFile) throws JDOMException, I


// get involved lines
for (final Object lineObj : file.getChildren()) {
final Element line = (Element) lineObj;
for (final Element line : fileElement.getChildren()) {

// parse line info
int lineNumber;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,18 @@ public ISpectra<String> loadSpectra() throws Exception {
*/
private Map<String, Boolean> traces() {
final Map<String, Boolean> traces = new HashMap<>();
for (final File trace : this.bugFolder.listFiles(new FileFilter() {
@Override
public boolean accept(final File pathname) {
if (!pathname.isFile()) {
return false;
}
final String fileExtension = FileUtils.getFileExtension(pathname);
if (0 != "xml".compareTo(fileExtension)) {
return false;
}
if (!pathname.getName().matches("^[pf]_.+")) {
return false;
}
return true;
for (final File trace : this.bugFolder.listFiles(pathname -> {
if (!pathname.isFile()) {
return false;
}
final String fileExtension = FileUtils.getFileExtension(pathname);
if (0 != "xml".compareTo(fileExtension)) {
return false;
}
if (!pathname.getName().matches("^[pf]_.+")) {
return false;
}
return true;
})) {
final boolean success = trace.getName().matches("^p_.+");
traces.put(trace.getAbsolutePath(), success);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static void perf(final String id) {
System.out.println(String.format("-- Begin: %s", id));
} else {
final long duration = System.currentTimeMillis() - benchmarks.get(id);
System.out.println(String.format("-- End: %s, Duration: %fs", id, new Double(duration) / 1000d));
System.out.println(String.format("-- End: %s, Duration: %fs", id, (double) duration / 1000d));
benchmarks.remove(id);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/fk/stardust/evaluation/sbfl/CreateRankings.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jdom.JDOMException;
import org.jdom2.JDOMException;

import fk.stardust.evaluation.ibugs.Experiment;
import fk.stardust.evaluation.ibugs.IBugsFaultLocations;
Expand Down Expand Up @@ -341,7 +341,7 @@ private String bench(final String id) {
// existing benchmark
final long duration = now - this.benchmarks.get(id);
this.benchmarks.remove(id);
return String.format("%f s", new Double(duration / 1000.0d));
return String.format("%f s", duration / 1000.0d);
} else {
this.benchmarks.put(id, now);
return null;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/fk/stardust/evaluation/sir/SIRExperiment.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ private double tarantula(final String line) {
final int cNF = Integer.parseInt(parts[3].trim());

// tarantula
final double part = new Double(cIF) / new Double(cIF + cNF);
return part / new Double(part + cIP / new Double(cIP + cNP));
final double part = (double) cIF / (double) (cIF + cNF);
return part / (part + (double) cIP / (double) (cIP + cNP));
}

public Ranking<Integer> getRanking() {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/fk/stardust/localizer/Ranking.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ public int getWorstRanking() {
* @return minWastedEffort
*/
public double getMinWastedEffort() {
return new Double(this.bestRanking - 1) / new Double(Ranking.this.nodes.size());
return (double) (this.bestRanking - 1) / (double) Ranking.this.nodes.size();
}

/**
Expand All @@ -350,7 +350,7 @@ public double getMinWastedEffort() {
* @return maxWastedEffort
*/
public double getMaxWastedEffort() {
return new Double(this.worstRanking - 1) / new Double(Ranking.this.nodes.size());
return (double) (this.worstRanking - 1) / (double) Ranking.this.nodes.size();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ public Ranking<T> localize(final ISpectra<T> spectra) {
}

// compute top-K nodes per ranking metric
final int k = new Double(spectra.getNodes().size() * 0.1 < 10 ? 10 : spectra.getNodes().size() * 0.1)
.intValue();
final int k = (int) (spectra.getNodes().size() * 0.1 < 10 ? 10 : spectra.getNodes().size() * 0.1);
final Map<IFaultLocalizer<T>, Set<INode<T>>> topK = this.topK(sbflRankings, k);


Expand Down Expand Up @@ -242,7 +241,7 @@ protected List<IFaultLocalizer<T>> selectOverlapBased(final ISpectra<T> spectra,
final Map<IFaultLocalizer<T>, Double> sortby = new HashMap<>();
for (final IFaultLocalizer<T> fl : rankings.keySet()) {
// score
final double oRate = new Double(all.size() - topK.get(fl).size()) / new Double(all.size());
final double oRate = (double) (all.size() - topK.get(fl).size()) / (double) all.size();
sortby.put(fl, oRate);
}

Expand Down Expand Up @@ -288,7 +287,7 @@ protected List<IFaultLocalizer<T>> selectBiasBased(final ISpectra<T> spectra,
numSum += lAll.get(curNode);
}

bias.put(fl, 1.0d - new Double(numSum) / (Math.sqrt(new Double(lSum)) * Math.sqrt(new Double(lAllSum))));
bias.put(fl, 1.0d - (double) numSum / (Math.sqrt((double) lSum) * Math.sqrt((double) lAllSum)));
}

// select'em
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ public Ranking<T> localize(final ISpectra<T> spectra) {
tf.add("f");

// create an attribute for each component
final Map<INode<T>, Attribute> attributeMap = new HashMap<INode<T>, Attribute>();
final ArrayList<Attribute> attributeList = new ArrayList<Attribute>(); // NOCS: Weka needs ArrayList..
final Map<INode<T>, Attribute> attributeMap = new HashMap<>();
final ArrayList<Attribute> attributeList = new ArrayList<>(); // NOCS: Weka needs ArrayList..
for (final INode<T> node : nodes) {
final Attribute attribute = new Attribute(node.toString(), tf);
attributeList.add(attribute);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/fk/stardust/localizer/sbfl/Ample.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public Ample() {

@Override
public double suspiciousness(final INode<T> node) {
final Double left = new Double(node.getIF()) / new Double(node.getIF() + node.getNF());
final Double right = new Double(node.getIS()) / new Double(node.getIS() + node.getNS());
final double left = (double) node.getIF() / (double) (node.getIF() + node.getNF());
final double right = (double) node.getIS() / (double) (node.getIS() + node.getNS());
return Math.abs(left - right);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/fk/stardust/localizer/sbfl/Anderberg.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public Anderberg() {

@Override
public double suspiciousness(final INode<T> node) {
return new Double(node.getIF()) / new Double(node.getIF() + 2.0d * (node.getNF() + node.getIS()));
return (double) node.getIF() / (double) (node.getIF() + 2.0d * (node.getNF() + node.getIS()));
}

@Override
Expand Down
Loading