Skip to content

Commit

Permalink
Programming exercises: Add blackbox tests as another Java project type (
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisknedl authored Sep 16, 2023
1 parent 9567be4 commit 12772a4
Show file tree
Hide file tree
Showing 38 changed files with 1,472 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ private ProjectType getConfiguredProjectType(final ProjectType actualProjectType
case XCODE -> ProjectType.XCODE;
case FACT -> ProjectType.FACT;
case GCC -> ProjectType.GCC;
case MAVEN_BLACKBOX -> ProjectType.MAVEN_BLACKBOX;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
*/
public enum ProjectType {

MAVEN_MAVEN, PLAIN_MAVEN, PLAIN, XCODE, FACT, GCC, PLAIN_GRADLE, GRADLE_GRADLE;
MAVEN_MAVEN, PLAIN_MAVEN, PLAIN, XCODE, FACT, GCC, PLAIN_GRADLE, GRADLE_GRADLE, MAVEN_BLACKBOX;

public boolean isMaven() {
return this == MAVEN_MAVEN || this == PLAIN_MAVEN;
return this == MAVEN_MAVEN || this == PLAIN_MAVEN || this == MAVEN_BLACKBOX;
}

public boolean isGradle() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public class FileService implements DisposableBean {
/**
* These directories get falsely marked as files and should be ignored during copying.
*/
private static final List<String> IGNORED_DIRECTORY_SUFFIXES = List.of(".xcassets", ".colorset", ".appiconset", ".xcworkspace", ".xcodeproj", ".swiftpm");
private static final List<String> IGNORED_DIRECTORY_SUFFIXES = List.of(".xcassets", ".colorset", ".appiconset", ".xcworkspace", ".xcodeproj", ".swiftpm", ".tests");

@Override
public void destroy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class JenkinsProgrammingLanguageFeatureService extends ProgrammingLanguag
public JenkinsProgrammingLanguageFeatureService() {
// Must be extended once a new programming language is added
programmingLanguageFeatures.put(EMPTY, new ProgrammingLanguageFeature(EMPTY, false, false, false, false, false, List.of(), false, true, false));
programmingLanguageFeatures.put(JAVA,
new ProgrammingLanguageFeature(JAVA, true, true, true, true, false, List.of(PLAIN_GRADLE, GRADLE_GRADLE, PLAIN_MAVEN, MAVEN_MAVEN), true, true, false));
programmingLanguageFeatures.put(JAVA, new ProgrammingLanguageFeature(JAVA, true, true, true, true, false,
List.of(PLAIN_GRADLE, GRADLE_GRADLE, PLAIN_MAVEN, MAVEN_MAVEN, MAVEN_BLACKBOX), true, true, false));
programmingLanguageFeatures.put(KOTLIN, new ProgrammingLanguageFeature(KOTLIN, true, false, true, true, false, List.of(), true, true, false));
programmingLanguageFeatures.put(PYTHON, new ProgrammingLanguageFeature(PYTHON, false, false, true, false, false, List.of(), false, true, false));
// Jenkins is not supporting XCODE at the moment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ private Optional<String> getProjectTypeName(final ProgrammingLanguage programmin
else if (projectType.isPresent() && projectType.get().isGradle()) {
return Optional.of("gradle");
}
else if (projectType.isPresent() && projectType.get().equals(ProjectType.MAVEN_BLACKBOX)) {
return Optional.of("blackbox");
}
// Maven is also the project type for all other Java exercises (also if the project type is not present)
else if (ProgrammingLanguage.JAVA.equals(programmingLanguage)) {
return Optional.of("maven");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.tum.in.www1.artemis.service.programming;

import static de.tum.in.www1.artemis.config.Constants.SETUP_COMMIT_MESSAGE;
import static de.tum.in.www1.artemis.domain.enumeration.ProjectType.isMavenProject;

import java.io.FileNotFoundException;
import java.io.IOException;
Expand Down Expand Up @@ -295,16 +296,8 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi

// First get files that are not dependent on the project type
final Path templatePath = ProgrammingExerciseService.getProgrammingLanguageTemplatePath(programmingExercise.getProgrammingLanguage()).resolve(TEST_DIR);

// Java both supports Gradle and Maven as a test template
Path projectTemplatePath = templatePath;
if (projectType != null && projectType.isGradle()) {
projectTemplatePath = projectTemplatePath.resolve("gradle");
}
else {
projectTemplatePath = projectTemplatePath.resolve("maven");
}
projectTemplatePath = projectTemplatePath.resolve("projectTemplate");
// Java supports multiple variants as test template
final Path projectTemplatePath = getJavaProjectTemplatePath(templatePath, projectType);

final Resource[] projectTemplate = resourceLoaderService.getResources(projectTemplatePath);
// keep the folder structure
Expand All @@ -315,6 +308,11 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi
setupJVMTestTemplateProjectTypeResources(resources, programmingExercise, repoLocalPath);
}

if (ProjectType.MAVEN_BLACKBOX.equals(projectType)) {
Path dejagnuLibFolderPath = repoLocalPath.resolve("testsuite").resolve("lib");
fileService.replaceVariablesInFileName(dejagnuLibFolderPath.toString(), PACKAGE_NAME_FILE_PLACEHOLDER, programmingExercise.getPackageName());
}

final Map<String, Boolean> sectionsMap = new HashMap<>();
// Keep or delete static code analysis configuration in the build configuration file
sectionsMap.put("static-code-analysis", Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled()));
Expand All @@ -332,6 +330,22 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi
commitAndPushRepository(resources.repository, "Test-Template pushed by Artemis", true, user);
}

private static Path getJavaProjectTemplatePath(final Path templatePath, final ProjectType projectType) {
Path projectTemplatePath = templatePath;

if (projectType != null && projectType.isGradle()) {
projectTemplatePath = projectTemplatePath.resolve("gradle");
}
else if (ProjectType.MAVEN_BLACKBOX.equals(projectType)) {
projectTemplatePath = projectTemplatePath.resolve("blackbox");
}
else {
projectTemplatePath = projectTemplatePath.resolve("maven");
}

return projectTemplatePath.resolve("projectTemplate");
}

/**
* Copies project type specific resources into the test repository.
*
Expand Down Expand Up @@ -378,7 +392,9 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource

setupBuildToolProjectFile(repoLocalPath, projectType, sectionsMap);

fileService.copyResources(testFileResources, resources.prefix, packagePath, false);
if (programmingExercise.getProjectType() != ProjectType.MAVEN_BLACKBOX) {
fileService.copyResources(testFileResources, resources.prefix, packagePath, false);
}

if (projectType != null) {
overwriteProjectTypeSpecificFiles(resources, programmingExercise, packagePath);
Expand Down Expand Up @@ -455,7 +471,7 @@ private void setupTestTemplateSequentialTestRuns(final RepositoryResources resou
sectionsMap.put("sequential", true);

// maven configuration should be set for kotlin and older exercises where no project type has been introduced where no project type is defined
final boolean isMaven = ProjectType.isMavenProject(projectType);
final boolean isMaven = isMavenProject(projectType);

final String projectFileName;
if (isMaven) {
Expand Down Expand Up @@ -527,7 +543,7 @@ private void setupBuildStage(final Path resourcePrefix, final Path templatePath,
final Path packagePath = buildStagePath.toAbsolutePath().resolve(TEST_DIR).resolve(PACKAGE_NAME_FOLDER_PLACEHOLDER).toAbsolutePath();

// staging project files are only required for maven
final boolean isMaven = ProjectType.isMavenProject(projectType);
final boolean isMaven = isMavenProject(projectType);
if (isMaven && stagePomXml.isPresent()) {
Files.copy(stagePomXml.get().getInputStream(), buildStagePath.resolve(POM_XML));
}
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ artemis:
java:
# possible overrides: maven, gradle
default: "ls1tum/artemis-maven-template:java17-18"
maven_blackbox: "ghcr.io/uni-passau-artemis/artemis-dejagnu:20"
kotlin:
# possible overrides: maven, gradle
default: "ls1tum/artemis-maven-template:java17-18"
Expand Down
Empty file.
31 changes: 31 additions & 0 deletions src/main/resources/templates/java/maven_blackbox/exercise/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${packageName}</groupId>
<artifactId>${exerciseNamePomXml}</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>${exerciseNamePomXml}</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>${project.basedir}/src</sourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>20</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ${packageName};

public class Client {
// TODO: Create and implement interactive command line handling
}
134 changes: 134 additions & 0 deletions src/main/resources/templates/java/maven_blackbox/readme
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Sorting with the Strategy Pattern

In this exercise, we want to implement sorting algorithms and control the program interactively via user input on the console.

**Note:** This project is using `Maven`! You have to import the project as Maven project (not as Eclipse project) as otherwise, errors will occur and you won't be able to work on this exercise.

### Part 1: User Input

First, there has to be a way for the user to communicate with the program.
The `Client` class should handle the user input. The following commands need to be supported by your implementation:

`add date1 date2 ...`<br>
Adds at least one date, but should also support multiple dates.<br>

`sort`<br>
Sorts the previously entered dates.<br>

`clear`<br>
Clears the list of dates.<br>

`help`<br>
Prints a dialog to the console that briefly explains the supported commands.<br>

`print`<br>
Prints the current list of dates to the console.<br>

`quit`<br>
Terminates the program.<br>

Using a `BufferedReader` might be a good starting point.



### Part 2: Sorting

We need to implement two sorting algorithms, in this case `MergeSort` and `BubbleSort`.

**You have the following tasks:**

1. **Implement Bubble Sort**<br>
Implement the method `performSort(List<Date>)` in the class `BubbleSort`. Make sure to follow the Bubble Sort algorithm exactly.

2. **Implement Merge Sort**<br>
Implement the method `performSort(List<Date>)` in the class `MergeSort`. Make sure to follow the Merge Sort algorithm exactly.

### Part 3: Strategy Pattern

We want the application to apply different algorithms for sorting a `List` of `Date` objects.
Use the strategy pattern to select the right sorting algorithm at runtime.

**You have the following tasks:**

1. **SortStrategy Interface**<br>
Create a `SortStrategy` interface and adjust the sorting algorithms so that they implement this interface.

2. **Context Class**<br>
Create and implement a `Context` class following the below class diagram

3. **Context Policy**<br>
Create and implement a `Policy` class following the below class diagram with a simple configuration mechanism:

1. **Select MergeSort**<br>
Select `MergeSort` when the List has more than 10 dates.

2. **Select BubbleSort**<br>
Select `BubbleSort` when the List has less or equal 10 dates.

4. Complete the `Client` class which demonstrates switching between two strategies at runtime.

@startuml

class Client {
}

class Policy {
+configure()
}

class Context {
-dates: List<Date>
+sort()
}

interface SortStrategy {
+performSort(List<Date>)
}

class BubbleSort {
+performSort(List<Date>)
}

class MergeSort {
+performSort(List<Date>)
}

MergeSort -up-|> SortStrategy
BubbleSort -up-|> SortStrategy
Policy -right-> Context: context
Context -right-> SortStrategy: sortAlgorithm
Client .down.> Policy
Client .down.> Context

hide empty fields
hide empty methods

@enduml

### Part 4: Tests

This section shows you which tests are passed by your implementation.

1. [task][Main method exists](MainMethodChecker)

2. [task][All lines have <= 80 characters](LineLengthChecker)

3. [task][Tests.txt exists and is not empty](FileExistsChecker)

4. [task][Public Tests](dejagnu[public])

5. [task][Advanced Tests](dejagnu[advanced])

6. [task][Secret Tests](dejagnu[secret])


### Part 5: Optional Challenges

(These are not tested)

1. Create a new class `QuickSort` that implements `SortStrategy` and implement the Quick Sort algorithm.

2. Make the method `performSort(List<Dates>)` generic, so that other objects can also be sorted by the same method.
**Hint:** Have a look at Java Generics and the interface `Comparable`.

3. Think about a useful decision in `Policy` when to use the new `QuickSort` algorithm.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
sort> help
add: adds the given Dates to the list (format: YYYY-MM-DD)
clear: empties the list
help: prints this text
print: prints the list
sort: sorts the list
quit: quits the program
sort>
Unknown command. Use 'help' to show available commands.
sort> help
add: adds the given Dates to the list (format: YYYY-MM-DD)
clear: empties the list
help: prints this text
print: prints the list
sort: sorts the list
quit: quits the program
sort> 2015-04-01
Unknown command. Use 'help' to show available commands.
sort> add 2015-04-01
sort> print
[Wed Apr 01 02:00:00 CEST 2015]
sort> add 2016-04-01
sort> add 2014-04-01
sort> add 2015-05-01 2015-04-30
sort> prinr
Unknown command. Use 'help' to show available commands.
sort> print
[Wed Apr 01 02:00:00 CEST 2015, Fri Apr 01 02:00:00 CEST 2016, Tue Apr 01 02:00:00 CEST 2014, Fri May 01 02:00:00 CEST 2015, Thu Apr 30 02:00:00 CEST 2015]
sort> sort
sort> print
[Tue Apr 01 02:00:00 CEST 2014, Wed Apr 01 02:00:00 CEST 2015, Thu Apr 30 02:00:00 CEST 2015, Fri May 01 02:00:00 CEST 2015, Fri Apr 01 02:00:00 CEST 2016]
sort> clear
sort> print
[]
sort> quit
31 changes: 31 additions & 0 deletions src/main/resources/templates/java/maven_blackbox/solution/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${packageName}</groupId>
<artifactId>${exerciseNamePomXml}-Solution</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>${exerciseNamePomXml} Solution</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>${project.basedir}/src</sourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>20</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
Loading

0 comments on commit 12772a4

Please sign in to comment.