Commit a1f2fb7c authored by Alexander's avatar Alexander
Browse files

Initial commit

parents
# Created by https://www.gitignore.io/api/java,eclipse,intellij
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Ruby plugin and RubyMine
/.rakeTasks
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/sonarlint
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# End of https://www.gitignore.io/api/java,eclipse,intellij
# IntelliJ
*.iml
.idea/
# Maven
target/
# If you are developing shared tests, you should uncomment the following lines
# src/edu/kit/informatik/
# !src/edu/kit/informatik/Terminal.java
*IOTestExample.io
# Checkstyle file
*.xml
# Assignment
*.pdf
\ No newline at end of file
# Kit assignment test framework
This repository provides classes to simplify testing KIT Programming 1 assignments.
For further information take a look at the [wiki](link).
Also have a look at our [Discord-Server](https://discord.gg/RVxBMVa).
## Describtion
This project serves a solid base for creating code for assignments.
It especially encourages beginners to start test-driven-development, use git and the powerful features of an modern IDE.
## Quick start
I really recommend to use [IntelliJ]() as IDE. The Ultimate version is free for students and provides many features you don't want to miss.
### Git
The first thing you have to check is that [git](https://git-scm.com/download) is installed on your system. You can check this by opening a command prompt and by typing 'git'.
+ **On windows** git isn't [installed](https://git-scm.com/download) by default
+ **On linux and mac** git is mostly installed by default. If it isn't, just install the **git** package on your system.
### Download and import the files in a project
First you have to go to the start window of IntelliJ (close any opened project).
There you can click on **Check out from Version Control** and select **git**.
In there you can paste in the git link of this repo: https://git.scc.kit.edu/hdlex/assignment-test-framework.git
If you edit the **Parent Directory** here you may have to edit it later when creating the project.
Click **clone**.
IntelliJ now asks you to create a new Project. Click **yes**.
You can continue clicking next until you have to select the Project SDK. There you have to add your [JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html) by telling IntelliJ where to find it.
After that click **next** and then **finish**. Your project will now be created and opened.
### Setup the new project
Before you can start building, you have to add **JUnit 5.0** to the class-path of your project.
We can let IntelliJ do this work for us.
To do so you have to search for an junit-import. So just hit Ctrl-Shift-F (search in all files), type junit and hit Enter.
Now your cursor should be at a red marked junit, so just hit ALT+ENTER (hotfix) and select **JUnit 5.0**.
The project should compile now. You can verify this by pressing **CTRL+F9** (Build Project).
### Start programming
You now can start programming just like any other project.
You probably want to add your `.java` source files into the `edu.kit.informatik` package.
### Writing a test
You now can write your first test. To switch files fast, just hit Ctrl-Shift+N.
First go to DummyMain.java in test\java\utility and replace the present Main class with your one.
Now go to SimpleTests.java in test\java\tests.
Here you can see a simple test function.
The easiest way to create a test is by specifying an input-output-file (io-file).
Io-files are resources loaded by tests. In a java project resource files should be separated from code files.
Therefore there is a resource folder in the test folder (src/test/resources).
SimpleTests has already a folder containing the io-file for the firstSimpleTest.
You can **navigate to the io file** by selecting firstSimpleTest and hitting Ctrl+Shift+N.
#### IO Files
The syntax of io files should be straight forward. You may recognize this syntax from your assignment sheets.
The following rules apply:
+ A line starting with '**>** ' models an input
+ The following lines after an input line is the expected output for that input.
+ If an expected output ends with '**...**', the test expects the output to start with the specified text
+ Error messages can be expected with the technique above or by specifying an example error message.
Therefore a line starting with 'Error, ' is treated like a generic error message.
+ The first lines before the first input line are ignored and therefore can be used for commenting.
+ A **quit is automatically added** by the test.
### Run tests
Before you can run a test, you have to tell it what to test. This can be done by editing the **extended** class of the provided **DummyMain** in the according directory of the test.
So hit Ctrl+Shift+N to search for your dedicated DummyMain (probably you want to edit the file in **src/test/java/utility**)
To run all tests in a folder or class right-click on it and select '**Run Tests ...**'.
\ No newline at end of file
package edu.kit.informatik;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
/**
* This class is a drop in replacement for the KIT Terminal class.
* It exactly functions as before but it can also be used by tests.
* The comments are left as they were originally, to avoid confusion by not so experienced programmers.
*
* So just throw away your old Terminal class and call it a day.
*
* @author Alexander Sommer (uhflp@student.kit.edu)
* @author Jon Amos Fehling
* @author Benjamin Takacs
* @since 23.01.2018
*/
public final class Terminal {
/**
* This field determines whether the current execution of the program is a test
*/
public static boolean isTest = false;
/**
* If enabled Terminal creates a file with TestPairs of the current run
*/
public static boolean isTestCreation = false;
public static boolean useMyErrorMessagesInTestCreation = true;
public static final String IO_FILE_COMMAND_LINE_ARGS_PREFIX = "! ";
private static StringBuilder testPairFile = new StringBuilder();
/**
* Progressbar stuff
*/
private static boolean showTestProgress = false;
private static int inputCount = 1;
private static int numInput = 0;
private static long time = 0;
/**
* This field represents the input from a test to a tested program
*/
public static final LinkedList<String> IN_TEST = new LinkedList<>();
/**
* This field represents the output from a tested program to a test
*/
public static final LinkedList<StringBuilder> OUT_TEST = new LinkedList<>();
/**
* Reads text from the "standard" input stream, buffering characters so as to provide for the efficient reading
* of characters, arrays, and lines. This stream is already open and ready to supply input data and corresponds
* to keyboard input.
*/
private static final BufferedReader IN = new BufferedReader(new InputStreamReader(System.in));
/**
* Private constructor to avoid object generation.
*
* @deprecated Utility-class constructor.
*/
@Deprecated
private Terminal() {
throw new AssertionError("Utility class constructor.");
}
/**
* Prints the given error-{@code message} with the prefix "{@code Error, }".
* <p>
* <p>More specific, this method behaves exactly as if the following code got executed:
* <blockquote><pre>
* Terminal.printLine("Error, " + message);</pre>
* </blockquote>
*
* @param message the error message to be printed
*/
public static void printError(final String message) {
String out = "Error, " + message;
if (isTest) {
if (OUT_TEST.getLast() == null) {
OUT_TEST.pollLast();
OUT_TEST.add(new StringBuilder());
} else {
OUT_TEST.getLast().append("\n");
}
OUT_TEST.getLast().append(out);
} else if (isTestCreation) {
System.err.println(out);
if (useMyErrorMessagesInTestCreation) {
testPairFile.append(out);
testPairFile.append("\n");
} else {
testPairFile.append("Error, ...\n");
}
} else {
System.err.println(out);
}
}
/**
* Prints the string representation of an {@code Object} and then terminate the line.
* <p>
* <p>If the argument is {@code null}, then the string {@code "null"} is printed, otherwise the object's string
* value {@code obj.toString()} is printed.
*
* @param object the {@code Object} to be printed
* @see String#valueOf(Object) String#valueOf(Object)
*/
public static void printLine(final Object object) {
if (isTest) {
if (OUT_TEST.getLast() == null) {
OUT_TEST.pollLast();
OUT_TEST.add(new StringBuilder());
} else {
OUT_TEST.getLast().append("\n");
}
OUT_TEST.getLast().append(object);
} else if (isTestCreation) {
System.out.println(object);
testPairFile.append(String.valueOf(object)).append("\n");
} else {
System.out.println(object);
}
}
/**
* Prints an array of characters and then terminates the line.
* <p>
* <p>If the argument is {@code null}, then a {@code NullPointerException} is thrown, otherwise the value of {@code
* new String(charArray)}* is printed.
*
* @param charArray an array of chars to be printed
* @see String#valueOf(char[]) String#valueOf(char[])
*/
public static void printLine(final char[] charArray) {
/*
* Note: This method's sole purpose is to ensure that the Terminal-class behaves exactly as
* System.out regarding output. (System.out.println(char[]) calls String.valueOf(char[])
* which itself returns 'new String(char[])' and is therefore the only method that behaves
* differently when passing the provided parameter to the System.out.println(Object)
* method.)
*/
printLine((Object) charArray);
}
/**
* Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return
* ('\r'), or a carriage return followed immediately by a linefeed.
*
* @return a {@code String} containing the contents of the line, not including any line-termination characters, or {@code null} if the end of the stream has been reached
*/
public static String readLine() {
if (!isTest)
try {
String in = IN.readLine();
if (isTestCreation && !in.equals("quit")) {
testPairFile.append("> ").append(in).append("\n");
}
return in;
} catch (final IOException e) {
/*
* The IOException will not occur during testExamples executed by the praktomat, therefore the
* following RuntimeException does not have to get handled.
*/
throw new RuntimeException(e);
}
else {
if (showTestProgress) {
numInput++;
if (numInput % (inputCount / 100) == 0) {
long t = System.nanoTime();
System.out.printf("%03d%% +%.2f ms%n", Math.round((double) numInput / inputCount * 100.0)
, (t - time) / 1000000.0);
time = t;
if (numInput == inputCount) {
System.out.println();
}
}
}
//If the program outputted nothing we still have null which means "no output"
OUT_TEST.add(null);
assert !IN_TEST.isEmpty()
: "Either the executed test doesn't have quit as last input\n"
+ "or your quitting mechanism doesn't work properly.\n"
+ "Expect the second option or check the test!";
return IN_TEST.poll();
}
}
/**
* Reads the file with the specified path and returns its content stored in a {@code String} array, whereas the
* first array field contains the file's first line, the second field contains the second line, and so on.
*
* @param path the path of the file to be read
* @return the content of the file stored in a {@code String} array
*/
public static String[] readFile(final String path) {
assert !isTest : "Read file isn't supported by a test yet :(";
try (final BufferedReader reader = new BufferedReader(new FileReader(path))) {
return reader.lines().toArray(String[]::new);
} catch (final IOException e) {
/*
* You can expect that the praktomat exclusively provides valid file-paths. Therefore
* there will no IOException occur while reading in files during the testExamples, the
* following RuntimeException does not have to get handled.
*/
throw new RuntimeException(e);
}
}
/**
* Save test pairs to file.
*
* @param path the path of file
*/
public static void saveInputOutputPairs(String path) {
if (isTest) {
System.err.println("Your program is still in test-creation-mode!");
return;
}
try (PrintWriter out = new PrintWriter(path)) {
testPairFile.deleteCharAt(testPairFile.length() - 1);
out.print("Automatically created test\n" + testPairFile.toString());
} catch (FileNotFoundException e) {
System.out.println("Unable to open file '" + path + "' for saving test pairs.");
}
System.out.println("Successfully created '" + path + "'");
}
/**
* Save test paris to timestamped file.
*/
public static void saveInputOutputPairs() {
String path = "testPairs_" + new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss'.io'").format(new Date());
saveInputOutputPairs(path);
}
/**
* This automatically adds the specified command line args to the test creation
*
* @param args are the args to add
*/
public static void startTestCreation(String[] args) {
isTestCreation = true;
if (args != null && args.length > 0) {
testPairFile.append(IO_FILE_COMMAND_LINE_ARGS_PREFIX);
for (String arg : args) {
testPairFile.append(arg);
testPairFile.append(" ");
}
testPairFile.deleteCharAt(testPairFile.length() - 1);
testPairFile.append("\n");
}
}
/**
* This automatically adds the specified command line args to the test creation
*
* @param args are the args to add
* @param doNotUseMyErrorMessages tells the program to use 'Error, ...' instead of the error-msges for io-files
*/
public static void startTestCreation(String[] args, boolean doNotUseMyErrorMessages) {
useMyErrorMessagesInTestCreation = !doNotUseMyErrorMessages;
startTestCreation(args);
}
public static void setupShowProgress(boolean showTestProgress, int inputCount) {
Terminal.showTestProgress = showTestProgress;
Terminal.inputCount = inputCount;
Terminal.numInput = 0;
time = System.nanoTime();
}
}
Put your code files in here (or in another package :D)
You can develop in here.
The Terminal class works just like the old one.
\ No newline at end of file
package program_examples;
import edu.kit.informatik.Terminal;
/**
* @author Alexander Sommer
* @since 23.01.2018
*/
public class FancyProgram {
public static void main(String[] args) {
String input;
while (!(input = Terminal.readLine()).equals("quit")) {
switch (input) {
case "msg":
Terminal.printLine("WABBALUBBADUPDUP!");
break;
case "pi":
Terminal.printLine(Math.PI);
break;
case "meaning of life":
Terminal.printLine(42);
break;
case "error":
Terminal.printError("the Praktomat is working!");
break;
case "dragon":
Terminal.printLine("O=- .- -. -=O");
Terminal.printLine("H /( )\\ H");
Terminal.printLine("| | -^^- | |");
Terminal.printLine(" \\_ `' _/");
Terminal.printLine("| \\ ) |");
Terminal.printLine("H )/ H");
Terminal.printLine("O=- (' -=O");
break;
case "quit":
break;
default:
Terminal.printError("unknown command.");
}
}
}
}
package program_examples;
import edu.kit.informatik.Terminal;
/**
* This shows how to create a test by interacting with the program
*
* @author Alexander Sommer
* @since 23.01.2018
*/
public class FancyProgramTestCreation {
public static void main(String[] args) {
Terminal.isTestCreation = true;
FancyProgram.main(args);
Terminal.saveInputOutputPairs("IOTestExample.io");
}
}
package program_examples;
public class Main {
public static void main(String[] args) {
System.out.println("========================================");
System.out.println(" __________________________________");
System.out.println(