Select Git revision
ApplicationMain.java
Forked from
Ho Dac Hai / COMP90015-DSAss2-InfinityMonkeys-remaster
Source project has a limited visibility.
Fuzzer.java 12.16 KiB
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Random;
/* a stub for your team's fuzzer */
public class Fuzzer {
private static final String OUTPUT_FILE = "fuzz.txt";
// The percentage of outputs that will start with a full stack
private static final int STACK_FULL_PERCENTAGE = 10;
// The percentage of inputs that will be incorrect
private static final int INPUT_ERROR_PERCENTAGE = 5;
// The percentage of instructions that will be incorrect
private static final int LINE_ERROR_PERCENTAGE = 5;
// Limit on generation of inputs
private static final int NUMBER_TO_GENERATE = 10;
// Instruction number range for each input
private static final int INSTRUCTION_MIN = 0;
private static final int INSTRUCTION_MAX = 100;
// Maximum variable name length
private static final int VAR_NAME_LENGTH_MAX = 100;
private static final int VAR_ASCII_MIN = 33;
private static final int VAR_ASCII_MAX = 127;
// Variable range
private static final int VAR_MIN = -2147483648;
private static final int VAR_MAX = 2147483647;
// Maximum number of items in stack
private static final int MAX_STACK_SIZE = 512;
// Random number generator
private static Random rand = new Random(System.currentTimeMillis());
private static ArrayList<String> vars = new ArrayList<>();
public static void main(String[] args) throws IOException {
System.out.println(Instruction.getBNF());
FileOutputStream out = null;
PrintWriter pw = null;
try {
out = new FileOutputStream(OUTPUT_FILE);
pw = new PrintWriter(out);
/* We just print one instruction.
Hint: you might want to make use of the instruction
grammar which is effectively encoded in Instruction.java */
// pw.print(getStaticTests());
pw.println(generateMultipleInputs());
}catch (Exception e){
e.printStackTrace(System.err);
System.exit(1);
}finally{
if (pw != null){
pw.flush();
}
if (out != null){
out.close();
}
}
}
/***
* Generates a list of different inputs for the program
*
* @return list of input strings
*/
private static String generateMultipleInputs(){
// Initiate variables
StringBuilder result = new StringBuilder();
// For debugging purposes
int generated = 0;
// Loop to create list of inputs
while (generated < NUMBER_TO_GENERATE) {
// Determine if the line will be correct or not
result.append(generateInput(false,
INSTRUCTION_MAX));
// Increment generated
generated += 1;
}
return result.toString();
}
/***
* Generates a line of input for the program
*
* @param correct flag, which determines if the line will be correctly formulated
* @param numInstructions for the line
* @return the concatenated input for the program as a string
*/
private static String generateInput(boolean correct, long numInstructions){
int stackSize = 0;
int counter = 0;
StringBuilder result = new StringBuilder();
if (rand.nextInt(100) < STACK_FULL_PERCENTAGE) {
for ( int i = 0 ; i < MAX_STACK_SIZE ; i++ ) {
result.append(completeInstruction(true, Instruction.PUSH));
stackSize++;
}
}
if (correct) {
while (counter < numInstructions) {
Instruction newInstr = Instruction.getRandomInstruction(stackSize);
stackSize = stackSize + newInstr.getStackChange();
result.append(completeInstruction(true, newInstr));
counter += 1;
}
} else {
while (counter < numInstructions) {
Instruction newInstr;
if (rand.nextInt(100) < LINE_ERROR_PERCENTAGE){
newInstr = Instruction.getRandomInstruction(2);
result.append(completeInstruction(false, newInstr));
} else {
newInstr = Instruction.getRandomInstruction(stackSize);
result.append(completeInstruction(true, newInstr));
}
stackSize = stackSize + newInstr.getStackChange();
if (stackSize < 0){
stackSize = 0;
}
counter += 1;
}
}
return result.toString();
}
/***
* Adds parameters to an individual instruction
*
* @param correct flag
* @param instruction type
* @return string with parameter
*/
private static String completeInstruction(boolean correct, Instruction instruction){
String name = "";
switch (instruction) {
case PUSH:
if (correct) {
// If correct, generate as usual
name = " " + ((Integer) randomRange(VAR_MIN, VAR_MAX)).toString();
} else {
// If incorrect, increase the range to outside +- int31_t
name = " " + ((Long) (randomRange(-1,1)*((long) VAR_MAX + (long) randomRange(0, VAR_MAX)))).toString();
}
break;
case LOAD:
case REM:
// If not correct, make up a name not in the list
if (!correct){
name = generateName();
}
// If no variables, return empty string
else if (vars.size() == 0){
return "";
}
// Otherwise, get a variable name from the list
else {
int index = rand.nextInt(vars.size());
name = " " + vars.get(index);
vars.remove(index);
}
break;
case STORE:
// Make up a name
name = name + generateName();
vars.add(name);
name = " " + name;
break;
case SAVE:
name = " " + generateName() + ".txt";
break;
case PLUS:
case SUB:
case MULT:
case DIV:
case POP:
case LIST:
case PRINT:
break;
}
return instruction.getOpcode() + name + "\n";
}
/***
* Generates a random name not longer than VAR_NAME_LENGTH_MAX
* Characters are bounded by ASCII indexes at VAR_ASCII_MIN and VAR_ASCII_MAX
*
* @return the name generated
*/
private static String generateName(){
StringBuilder name = new StringBuilder();
int counter = 0;
// Randomise the length of the string
int length = rand.nextInt(VAR_NAME_LENGTH_MAX);
// Add random bounded characters to string
while (counter < length){
name.append((char) randomRange(VAR_ASCII_MIN, VAR_ASCII_MAX));
counter += 1;
}
return name.toString();
}
private static int randomRange(int min, int max){
// Remove negatives and get around int limitations
if (min == VAR_MIN){
return 2* (rand.nextInt(max) + (min/2));
} else if (min < 0){
max = max - min;
return rand.nextInt(max) + min;
}
return min + rand.nextInt(max - min);
}
/***
* Get the desired static boundary tests
*
* @return a string containing all of the boundary tests' instructions
*/
private static String getStaticTests() {
// Note. Some operations will crash dc if performed, so they cannot be tested
// Examples include *, /, -, +, pop, store operations on empty stack
StringBuilder result = new StringBuilder();
// Test opreations that need variables on no variables defined
result.append(Instruction.LIST.getOpcode() + "\n");
result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
result.append(Instruction.REM.getOpcode() + " VAR1\n");
// Test operations that use stack on empty stack
result.append(Instruction.PRINT.getOpcode() + "\n");
// Prep for next tests
result.append(Instruction.PUSH.getOpcode() + " 5\n");
result.append(Instruction.STORE.getOpcode() + " VAR1\n");
result.append(Instruction.PUSH.getOpcode() + " 10\n");
result.append(Instruction.STORE.getOpcode() + " VAR2\n");
result.append(Instruction.SAVE.getOpcode() + "\n");
// Test incorrect arguements for operation
result.append(Instruction.LOAD.getOpcode() + " VAR3\n");
// Test Variables stored and used corectly
result.append(Instruction.LIST.getOpcode() + "\n");
result.append(Instruction.PRINT.getOpcode() + "\n");
result.append(Instruction.LOAD.getOpcode() + " VAR2\n");
result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
result.append(Instruction.PRINT.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
result.append(Instruction.PRINT.getOpcode() + "\n");
result.append(Instruction.REM.getOpcode() + " VAR2\n");
result.append(Instruction.LIST.getOpcode() + "\n");
result.append(Instruction.LOAD.getOpcode() + " VAR2\n");
result.append(Instruction.PRINT.getOpcode() + "\n");
result.append(Instruction.STORE.getOpcode() + " VAR1\n");
result.append(Instruction.LIST.getOpcode() + "\n");
result.append(Instruction.LOAD.getOpcode() + " VAR1\n");
result.append(Instruction.STORE.getOpcode() + " VAR1\n");
result.append(Instruction.LIST.getOpcode() + "\n");
result.append(Instruction.REM.getOpcode() + " VAR1\n");
// Test Plus operation
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
result.append(Instruction.PLUS.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.PUSH.getOpcode() + " 1\n");
result.append(Instruction.PLUS.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
// Test Subtract operation
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.SUB.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
result.append(Instruction.PUSH.getOpcode() + " 1\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
result.append(Instruction.SUB.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
// Test Divide operation
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.DIV.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
result.append(Instruction.PUSH.getOpcode() + " 1\n");
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MIN + "\n");
result.append(Instruction.DIV.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
// Test Multiply operation
result.append(Instruction.PUSH.getOpcode() + " "+ VAR_MAX + "\n");
result.append(Instruction.PUSH.getOpcode() + " 2\n");
result.append(Instruction.MULT.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
result.append(Instruction.PUSH.getOpcode() + " 2\n");
result.append(Instruction.PUSH.getOpcode() + " "+ Math.floorDiv(VAR_MIN, 2) + "\n");
result.append(Instruction.MULT.getOpcode() + "\n");
result.append(Instruction.POP.getOpcode() + "\n");
return result.toString();
}
}