├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── arrays.javauto ├── controlFlow.javauto ├── conversion.javauto ├── globalVariables.javauto ├── javaIntegration.javauto ├── logicalOperators.javauto ├── mathOperators.javauto ├── notifier.javauto ├── stringFormatting.javauto ├── structsData.javauto ├── udf.javauto ├── userInput.javauto └── variables.javauto ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── automation │ │ └── javauto │ │ ├── Javauto.java │ │ ├── compiler │ │ ├── CustomJarCompiler.java │ │ ├── CustomJavaCompiler.java │ │ └── DealWithCompilerErrors.java │ │ ├── debugger │ │ └── SimpleDebugger.java │ │ └── parser │ │ └── Create.java └── resources │ └── Javauto.java └── test ├── java └── com │ └── automation │ └── javauto │ └── test │ ├── JavautoTest.java │ └── TestPanel.java └── resources ├── fermat.txt └── script └── tests.javauto /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | test-output 3 | apidocs 4 | apidocs.json 5 | .classpath 6 | .project 7 | .settings 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | matrix: 7 | fast_finish: true 8 | 9 | before_install: 10 | - "export DISPLAY=:99.0" 11 | - "sh -e /etc/init.d/xvfb start" 12 | 13 | script: 14 | - "mvn clean install" 15 | - "java -jar /home/travis/build/Javauto/javauto-core/target/javauto-1.1.0.jar /home/travis/build/Javauto/javauto-core/src/test/resources/script/tests.javauto" 16 | - "java -jar tests.jar" 17 | 18 | sudo: false 19 | 20 | notifications: 21 | webhooks: 22 | urls: 23 | - https://webhooks.gitter.im/e/56a42f65b462c237bbe9 24 | on_success: change 25 | on_failure: always 26 | on_start: false 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Javauto 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![alt tag](https://cloud.githubusercontent.com/assets/3797402/12898899/c04d2f5c-ce8d-11e5-96ad-0d35c37a9f9a.png) 2 | 3 | Javauto is a programming language for automation. Derived from Java, it is a cross platform alternative to something like AutoIt. 4 | 5 | ![build](https://travis-ci.org/Javauto/javauto-core.svg) [![Join the chat at https://gitter.im/Javauto/javauto-core](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Javauto/javauto-core?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | 7 | # Links 8 | 9 | * Website: http://javauto.github.io/ 10 | * Gitter.im chats: [javauto-core](https://gitter.im/Javauto/javauto-core?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge#) 11 | * [Javauto Helper](https://github.com/Javauto/javauto-helper) exists to simplify the process of finding mouse coordinates and pixel colors. 12 | * [Java Lookup](https://github.com/Javauto/javauto-lookup) helps a user find relevant documentation for a specific function. 13 | * StackOverflow: questions with the [javauto](http://stackoverflow.com/questions/tagged/javauto) tag 14 | * Syntax highlighting and auto completion for Javauto files in [Notepad++](https://github.com/Javauto/javauto-notepad-plusplus) 15 | * If you're looking to report a bug, please use the [issue tracker](https://github.com/Javauto/javauto-core/issues). 16 | * [Twitter account](https://twitter.com/JavautoL) 17 | 18 | # Projects Using Javauto 19 | 20 | * [adbutil](https://github.com/ohtejera/adbutil) - A simple Javauto (cross platform) wrapper around Android Debug Bridge to enable multi device support. 21 | * [ImperiusGeorge Client](https://github.com/ohtejera/JavautoImperiusGeorge) - A test automation library which drives off the UI of Android native applications. 22 | 23 | 24 | 25 | # License 26 | 27 | Javauto is licensed under the terms of the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 28 | -------------------------------------------------------------------------------- /examples/arrays.javauto: -------------------------------------------------------------------------------- 1 | // define two arrays 2 | String[] strArr = {"each", "of", "these", "is", "an", "element"}; 3 | int[] intArr = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34}; 4 | 5 | print( strArr[0] ); // print the first element of the string array 6 | strArr[0] = "new!"; // change the first element 7 | print( strArr[0] ); // print it again 8 | 9 | // we can get the size of the array with .length 10 | int strArrSize = strArr.length; // this will return 6, there are six elements 11 | 12 | // print the last element 13 | print( strArr[strArrSize-1] ); // the last element is one less than the length 14 | 15 | // print everything in the intArray 16 | print("Index\tValue"); 17 | for (int i = 0; i < intArr.length; i++) { 18 | print( toString(i) + "\t" + toString( intArr[i] ) ); 19 | } -------------------------------------------------------------------------------- /examples/controlFlow.javauto: -------------------------------------------------------------------------------- 1 | int a = -1; 2 | if (a > 0) { 3 | print( "%s is positive!" % ( toString(a) ) ); 4 | } else if (a < 0) { 5 | print( "%s is negative!" % ( toString(a) ) ); 6 | } else { 7 | // if it isn't positive or negative it's 0 8 | print( "%s is zero" % ( toString(a) ) ); 9 | } 10 | 11 | 12 | String name = "john"; 13 | if (name == "john") { // this compares the two addresses in memory, will not always be true 14 | print("This will not always happen"); 15 | } 16 | if (name.equals("john")) { // this compares the contents of the string, will equal true 17 | print("This should always happend"); 18 | } 19 | 20 | 21 | int i = 0; 22 | while ( i <= 5 ) { 23 | print(i); 24 | i = i + 1; // add one to i 25 | } 26 | 27 | for (int c = 0; c <= 5; c++) { 28 | print(c); 29 | } 30 | 31 | String[] alpha = {"a","b","c","d","e","f"}; 32 | for (String letter : alpha) { 33 | print(letter); 34 | } 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/conversion.javauto: -------------------------------------------------------------------------------- 1 | String input = input("Enter a number: "); // get their number as a string 2 | int number = toInt(input); // get number as an int 3 | print(input + " + 5 = " + toString(number + 5)); // add five to it and display as string 4 | print(number/2); // divide number by 2 (will return an integer) 5 | print(toDouble(number)/2); // convert number to double and then divide -------------------------------------------------------------------------------- /examples/globalVariables.javauto: -------------------------------------------------------------------------------- 1 | global String var; // let the compiler know it's global 2 | var = "A variable"; 3 | func void printVar() { 4 | print(var); // print our var 5 | } 6 | printVar(); -------------------------------------------------------------------------------- /examples/javaIntegration.javauto: -------------------------------------------------------------------------------- 1 | import java.util.Date; 2 | 3 | //both of the below are valid 4 | System.out.println("Printing with Java"); 5 | print("Printing with Javauto"); 6 | 7 | Date date = new Date(); 8 | // display time and date using toString() 9 | System.out.println(date.toString()); 10 | -------------------------------------------------------------------------------- /examples/logicalOperators.javauto: -------------------------------------------------------------------------------- 1 | int a = 10; 2 | int b = 3; 3 | int c = 3; 4 | boolean bool = true; 5 | 6 | print(a > b); // 10 > 3 => true 7 | print(b < a); // 3 < 10 => true 8 | print(b > c); // 3 is not greater than 3 => false 9 | print(b == c); // 3 does equal 3 => true 10 | print(c != a); // 3 does not equal 10 => true 11 | print(b >= c); // 3 is equal to 3, so greate than or equals works => true 12 | print(b <= c); // less than will also work => true 13 | 14 | print(bool); // true is true 15 | print(!bool); // !true is the same as not true = false 16 | 17 | // statements can be grouped in () 18 | print( !( (a + b) < c ) ); // evaluates to not (13 < 3). 13 is not less than 3. not (false) => true 19 | 20 | // the and operator is && 21 | print( (b < a) && (c < a) ); // both are true => true 22 | print( (b < a) && (a < c) ); // a is not less than c => false 23 | 24 | // the or operator is || 25 | print( (b < a) || (a < c) ); // as long as one is true or is satisfied => true 26 | print( (!bool) || (a < c) ); // if neither is true => false -------------------------------------------------------------------------------- /examples/mathOperators.javauto: -------------------------------------------------------------------------------- 1 | int a = 10; 2 | int b = 3; 3 | 4 | print("10 + 3 = " + (a + b)); // add the two 5 | print("10 x 3 = " + (a * b)); // multiply the two 6 | print("10 / 3 = " + (a / b)); // divide the two, since the result is in int it will be truncated, so instead of 3.333333333 it returns 3 7 | print("10 % 3 = " + (a % b)); // get the remainder. 10 divided by 3 has a remainder of 1 -------------------------------------------------------------------------------- /examples/notifier.javauto: -------------------------------------------------------------------------------- 1 | //Check program arguments. 2 | if(args.length == 0){ 3 | printHelp(); 4 | } 5 | 6 | if (!isFlagged(args, "-u") || !isFlagged(args, "-p") ) { 7 | printHelp(); 8 | } 9 | 10 | do { 11 | notify(getFlaggedArg(args, "-u")); 12 | sleep(toInt(getFlaggedArg(args, "-p"))); 13 | } while(true); 14 | 15 | // Print program help and exit. 16 | func void printHelp(){ 17 | print("Usage: notifier.jar -u URL -p Time (Inserts a fixed delay between httpGet [milliseconds])"); 18 | print("Example: java -jar notifier.jar -u http://www.javauto.org -p 1000 "); 19 | System.exit(0); 20 | } 21 | 22 | func void notify(String url){ 23 | String response = httpGet(url); 24 | if(response.isEmpty()){ 25 | print( "[ERROR] %s is not reachable! You may panic now." % (url) ); 26 | } else { 27 | print( "[OK] %s is online" % (url)); 28 | } 29 | } -------------------------------------------------------------------------------- /examples/stringFormatting.javauto: -------------------------------------------------------------------------------- 1 | String name = "John"; 2 | String greeting = "Hello %s, I'm %s." % (name, "Javauto"); 3 | print(greeting); -------------------------------------------------------------------------------- /examples/structsData.javauto: -------------------------------------------------------------------------------- 1 | // define a struct for a user datatype 2 | struct user { 3 | String ID; 4 | } 5 | 6 | // define a function that can return a variable of type user 7 | func user getUser() { 8 | user c = new user(); // create an instance of this type of variable 9 | c.ID = USER_NAME.toLowerCase() + "@" + SYSTEM_OS.toLowerCase(); // assign it an ID 10 | return c; // return all this data wrapped in our user datatype 11 | } 12 | 13 | // now we call this function and store the data in "us" 14 | user us = getUser(); 15 | 16 | // display its ID 17 | print("USER ID: %s" % (us.ID)); 18 | -------------------------------------------------------------------------------- /examples/udf.javauto: -------------------------------------------------------------------------------- 1 | //User Defined Functions 2 | 3 | // Define a function to move the mouse to random coordinates. 4 | // This function is void, meaning it doesn't return any value. 5 | func void randomMouseMove() { 6 | int x = intGetRandom(0, 500); // get a random int for x 7 | int y = intGetRandom(0, 500); // get a random int for y 8 | mouseMove(x,y); // move the mouse to these generated coordinates 9 | } 10 | 11 | msgBox("Moving the mouse to random coordinates..."); 12 | randomMouseMove(); // execute the function 13 | 14 | 15 | // This function tells us whether the mouse 16 | // is on the left side of the screen. 17 | func boolean isLeft() { 18 | int xCoord = cursorGetPos()[0]; // get the x mouse position 19 | 20 | if (xCoord < (SCREEN_WIDTH / 2)) { // if we're left of the half way point 21 | return true; 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | if (isLeft()) { 28 | print("The cursor is on the left side of the screen."); 29 | } else { 30 | print("The cursor is not on the left side of the screen."); 31 | } 32 | -------------------------------------------------------------------------------- /examples/userInput.javauto: -------------------------------------------------------------------------------- 1 | // get input from command line and print it 2 | String userResponse = input("Enter your name: "); // get user input from the console 3 | String greeting = "Hello " + userResponse + ", it's nice to meet you."; 4 | print(greeting); 5 | 6 | // get input from a dialog box and display response in a message box 7 | userResponse = inputBox("Enter your name"); 8 | greeting = "Hello " + userResponse + ", it's nice to meet you."; 9 | msgBox(greeting, "Hello There"); -------------------------------------------------------------------------------- /examples/variables.javauto: -------------------------------------------------------------------------------- 1 | // the type must be specified when defining each variable 2 | String str = "This is a string."; // Strings must be enclosed in double quotes 3 | int number = 100; 4 | double pi = 3.1415926535; 5 | boolean b = true; 6 | 7 | // since these variables have already been defined we don't have to specify their types 8 | str = "A different string."; 9 | number = number - 50; // subtract 50 from our number 10 | pi = pi * 2; // double pi's value 11 | b = false; // change b's value 12 | 13 | // print it all 14 | print(str); 15 | print(number); 16 | print(pi); 17 | print(b); -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.automation 5 | javauto 6 | 1.1.0 7 | 8 | Javauto 9 | http://javauto.org 10 | Javauto is a programming language for automation. 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.8 16 | 17 | 18 | 19 | 20 | junit 21 | junit 22 | 4.12 23 | 24 | 25 | 26 | org.assertj 27 | assertj-core 28 | 3.1.0 29 | 30 | 31 | 32 | commons-lang 33 | commons-lang 34 | 2.1 35 | 36 | 37 | 38 | org.codehaus.plexus 39 | plexus-utils 40 | 1.1 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-compiler-plugin 49 | 50 | ${maven.compiler.source} 51 | ${maven.compiler.target} 52 | 53 | 54 | 55 | maven-antrun-plugin 56 | 1.8 57 | 58 | 59 | copy-javauto-file 60 | package 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | run 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-jar-plugin 77 | 2.6 78 | 79 | 80 | com/automation/javauto/Javauto.class 81 | com/automation/javauto/Javauto$1.class 82 | 83 | 84 | 85 | true 86 | com.automation.javauto.parser.Create 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/java/com/automation/javauto/compiler/CustomJarCompiler.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.compiler; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedOutputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.util.Map; 11 | import java.util.jar.Attributes; 12 | import java.util.jar.JarEntry; 13 | import java.util.jar.JarOutputStream; 14 | import java.util.jar.Manifest; 15 | import java.util.zip.Deflater; 16 | 17 | /** 18 | * Takes a directory and adds each class file within it to a JAR file. 19 | * 20 | * @author matthew.downey 21 | * 22 | */ 23 | public class CustomJarCompiler { 24 | /* define constants for different terminal colors */ 25 | private static String GREEN = "\033[92m"; 26 | private static String YELLOW = "\033[93m"; 27 | private static String NORMAL = "\033[0m"; 28 | 29 | public static boolean colors = true; 30 | 31 | public static boolean verbose = false; 32 | 33 | public static void create(String output, String mainClass, String inputDir) 34 | throws IOException { 35 | if (!colors) { 36 | GREEN = ""; 37 | YELLOW = ""; 38 | NORMAL = ""; 39 | } 40 | verbose("Building " + GREEN + (new File(output)).getAbsolutePath() 41 | + NORMAL); 42 | Manifest manifest = new Manifest(); 43 | manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, 44 | "1.0"); 45 | manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, mainClass); 46 | JarOutputStream target = new JarOutputStream(new FileOutputStream( 47 | output), manifest); 48 | add(new File(inputDir), target); 49 | target.close(); 50 | } 51 | 52 | private static void add(File source, JarOutputStream target) 53 | throws IOException { 54 | BufferedInputStream in = null; 55 | try { 56 | if (source.isDirectory()) { 57 | String name = source.getPath().replace("\\", "/"); 58 | if (!name.isEmpty()) { 59 | if (!name.endsWith("/")) 60 | name += "/"; 61 | JarEntry entry = new JarEntry(name); 62 | entry.setTime(source.lastModified()); 63 | target.putNextEntry(entry); 64 | target.closeEntry(); 65 | } 66 | for (File nestedFile : source.listFiles()) 67 | add(nestedFile, target); 68 | return; 69 | } 70 | 71 | JarEntry entry = new JarEntry(source.getName()); 72 | entry.setTime(source.lastModified()); 73 | target.putNextEntry(entry); 74 | in = new BufferedInputStream(new FileInputStream(source)); 75 | 76 | byte[] buffer = new byte[1024]; 77 | while (true) { 78 | int count = in.read(buffer); 79 | if (count == -1) 80 | break; 81 | target.write(buffer, 0, count); 82 | } 83 | target.closeEntry(); 84 | verbose("\tadded " + YELLOW + source.getName() + NORMAL); 85 | } finally { 86 | if (in != null) 87 | in.close(); 88 | } 89 | } 90 | 91 | private static void verbose(String msg) { 92 | if (verbose) 93 | System.out.println(msg); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/automation/javauto/compiler/CustomJavaCompiler.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.compiler; 2 | 3 | import java.net.URI; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.ArrayList; 7 | import java.io.File; 8 | import java.io.IOException; 9 | 10 | import javax.tools.Diagnostic; 11 | import javax.tools.DiagnosticCollector; 12 | import javax.tools.JavaCompiler; 13 | import javax.tools.JavaFileObject; 14 | import javax.tools.SimpleJavaFileObject; 15 | import javax.tools.ToolProvider; 16 | import javax.tools.StandardLocation; 17 | import javax.tools.StandardJavaFileManager; 18 | import javax.tools.JavaCompiler.CompilationTask; 19 | import javax.tools.JavaFileObject.Kind; 20 | 21 | /** 22 | * Takes Java code and generates a class file. Errors are sent to 23 | * {@link DealWithCompilerErrors}. 24 | * 25 | * @author matthew.downey 26 | * 27 | */ 28 | public class CustomJavaCompiler { 29 | public static DiagnosticCollector compile(String name, 30 | String code, String outDir, String classpath) throws IOException { 31 | /* get JavaCompiler object to create the .class file */ 32 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 33 | 34 | /* throw an exception if there's an issue with the compiler */ 35 | if (compiler == null) { 36 | throw new NullPointerException( 37 | "Couldn't find java system compiler."); 38 | } 39 | 40 | /* get a file manager object that lets us control the output location */ 41 | StandardJavaFileManager fileManager = compiler.getStandardFileManager( 42 | null, null, null); 43 | 44 | /* tell the file manager where to put the generated class files */ 45 | fileManager.setLocation(StandardLocation.CLASS_OUTPUT, 46 | Arrays.asList(new File(outDir))); 47 | 48 | /* 49 | * tell the file manager where to look for related class files that may 50 | * be referenced 51 | */ 52 | fileManager.setLocation(StandardLocation.CLASS_PATH, 53 | Arrays.asList(new File(classpath))); 54 | 55 | /* 56 | * get a DiagnosticCollector object to hold a list of 57 | * potential errors 58 | */ 59 | DiagnosticCollector diagnostics = new DiagnosticCollector(); 60 | 61 | /* create a JavaFileObject from our source code and class name */ 62 | JavaFileObject file = new JavaSourceFromString(name, code); 63 | 64 | /* place our file as the only item in a list of files to be compiled */ 65 | Iterable compilationUnits = Arrays.asList(file); 66 | 67 | /* supply the compiler with all the information required to compile */ 68 | CompilationTask task = compiler.getTask(null, fileManager, diagnostics, 69 | null, null, compilationUnits); 70 | 71 | /* 72 | * compile it -- note that errors will be inserted into our diagnostics 73 | * variable 74 | */ 75 | boolean win = task.call(); 76 | 77 | /* win == true if there weren't compilation errors */ 78 | if (win) 79 | return null; 80 | else 81 | /* return errors */ 82 | return diagnostics; 83 | } 84 | } 85 | 86 | class JavaSourceFromString extends SimpleJavaFileObject { 87 | final String code; 88 | 89 | JavaSourceFromString(String name, String code) { 90 | super(URI.create("string:///" + name.replace('.', '/') 91 | + Kind.SOURCE.extension), Kind.SOURCE); 92 | this.code = code; 93 | } 94 | 95 | @Override 96 | public CharSequence getCharContent(boolean ignoreEncodingErrors) { 97 | return code; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/automation/javauto/compiler/DealWithCompilerErrors.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.compiler; 2 | 3 | import javax.tools.*; 4 | import java.io.*; 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Attempt to make any compiler errors from {@link CustomJavaCompiler} relevant 9 | * to the user's original Javauto code and display these errors. 10 | * 11 | * @author matthew.downey 12 | * 13 | */ 14 | public class DealWithCompilerErrors { 15 | /** 16 | * Handle errors that may crop up during compilation. This entails letting 17 | * the user know what caused the error and where. 18 | */ 19 | public static void dealWithIt( 20 | DiagnosticCollector compileErrors, 21 | String generatedCode, String userCode, String userCodeFileName) { 22 | for (Diagnostic diagnostic : compileErrors.getDiagnostics()) { 23 | /* get the text of the line the error appears on */ 24 | String line = getLine(diagnostic.getPosition(), generatedCode); 25 | 26 | /* 27 | * get all line numbers in the original code that contain the error 28 | * line 29 | */ 30 | ArrayList originalLineNums = getOriginalLineNums(line, 31 | userCode); 32 | 33 | /* if we only found it once in the original code we're all good! */ 34 | if (originalLineNums.size() == 1) { 35 | System.out 36 | .println(userCodeFileName 37 | + " line " 38 | + (originalLineNums.get(0) + 1) 39 | + "\n" 40 | + line 41 | + "\n" 42 | + diagnostic.getKind().toString().toLowerCase() 43 | + ": " 44 | + diagnostic.getMessage(null).replace( 45 | "java.lang.", "")); 46 | } 47 | 48 | /* 49 | * if we found it more than once specify where in the generated code 50 | * to look for it and tell them to use --generate 51 | */ 52 | else { 53 | String className = new File(userCodeFileName).getName().split( 54 | "\\.(?=[^\\.]+$)")[0]; 55 | System.out 56 | .println("Generated file: " 57 | + className 58 | + ".java line " 59 | + getLineNumber((int) diagnostic.getPosition(), 60 | generatedCode) 61 | + "\n" 62 | + line 63 | + "\n" 64 | + diagnostic.getKind().toString().toLowerCase() 65 | + ": " 66 | + diagnostic.getMessage(null).replace( 67 | "java.lang.", "")); 68 | System.out 69 | .println("This was an error in generated code -- to understand what caused the error please compile with the --generate flag to enable the writing of generated files. During compilation a directory called \"" 70 | + className 71 | + "/gen/\" will be created, and this directory will contain " 72 | + className 73 | + ".java, the file that caused the error."); 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Find the line that a character appears on based on the character 80 | * position. 81 | * 82 | * @param pos 83 | * the position of the character 84 | * @param generatedCode 85 | * the string the character position is in 86 | * @return the line number containing the character 87 | */ 88 | private static int getLineNumber(int pos, String generatedCode) { 89 | int line = 1; 90 | char[] genChars = generatedCode.toCharArray(); 91 | for (int i = 0; i < pos; i++) 92 | if (genChars[i] == '\n') 93 | line++; 94 | return line; 95 | } 96 | 97 | /** 98 | * Gets the line numbers in the user code of lines that exactly match the 99 | * given line of generated code. That way if a line of generated code causes 100 | * an error and appears only once in the user code we can inform the user of 101 | * the line of their code that causes an error. 102 | * 103 | * @param line 104 | * the line of generated code that causes an error 105 | * @param userCode 106 | * the user code file to match the line against 107 | * @return an ArrayList of lines that match the error line 108 | */ 109 | private static ArrayList getOriginalLineNums(String line, 110 | String userCode) { 111 | ArrayList lineNums = new ArrayList(); 112 | Integer l = 0; 113 | for (String userLine : userCode.split("\n")) { 114 | if (userLine.trim().equals(line.trim()) 115 | || removeComments(userLine).trim().equals(line.trim())) { 116 | lineNums.add(l); 117 | } 118 | l = l + 1; 119 | } 120 | return lineNums; 121 | } 122 | 123 | /** 124 | * Get the whole line that contains the error. 125 | * 126 | * @param startPosition 127 | * the Diagnostic.getPosition() value for the error 128 | * @param generatedCode 129 | * the code that caused the error 130 | * @return the line containing the error 131 | */ 132 | private static String getLine(long startPosition, String generatedCode) { 133 | /* get the line bounds */ 134 | int[] bounds = getLineBounds((int) startPosition, generatedCode); 135 | 136 | /* return the line based on the bounds */ 137 | return generatedCode.substring(bounds[0], bounds[1]); 138 | } 139 | 140 | private static int[] getLineBounds(int pos, String generatedCode) { 141 | /* 142 | * find the indexes of the "\n" characters on either side of the 143 | * position 144 | */ 145 | return new int[] { 146 | generatedCode.substring(0, pos).lastIndexOf("\n") + 1, 147 | pos + generatedCode.substring(pos).indexOf("\n") }; 148 | } 149 | 150 | private static String removeComments(String line) { 151 | ArrayList commentIgnores = getIgnoreIndexes(line).get(0); 152 | String temp = ""; 153 | for (int i = 0; i < line.length(); i++) { 154 | if (!inIgnoredText(i, commentIgnores)) 155 | temp = temp + line.substring(i, i + 1); 156 | } 157 | return temp; 158 | } 159 | 160 | private static boolean inIgnoredText(int charIndex, 161 | ArrayList ignoredIndexes) { 162 | /* check each set of bounds to see if they hold our charIndex */ 163 | for (Integer[] i : ignoredIndexes) { 164 | if (charIndex >= i[0] && charIndex <= i[1]) 165 | return true; 166 | } 167 | 168 | /* if we got to here we haven't found it inside any of the bounds */ 169 | return false; 170 | } 171 | 172 | /** 173 | * Build a list of character indexes that should be ignored during 174 | * processing. Characters to be ignored are those inside of comments, string 175 | * literals, and character literals. This function returns the bounds of 176 | * indexes of characters and literals in two separate lists. 177 | * 178 | * @param code 179 | * the string to generate this list of bounds for 180 | * @return returns two ArrayList objects, wrapped inside of one 181 | * ArrayList, with the format [comment indexes, literal indexes]. 182 | * Then each of those elements is a list with the format [start 183 | * ignore index, end ignore index]. 184 | */ 185 | private static ArrayList> getIgnoreIndexes(String code) { 186 | /* Lists to hold bounds for both comments and literals */ 187 | ArrayList commentIndexes = new ArrayList(); 188 | ArrayList literalIndexes = new ArrayList(); 189 | 190 | /* 191 | * List to hold our other two lists, so that the user can separate them 192 | * at will 193 | */ 194 | ArrayList> finalValues = new ArrayList>(); 195 | 196 | /* 197 | * iterate through character by character looking for comments and 198 | * literals 199 | */ 200 | char[] codeChars = code.toCharArray(); 201 | int index = 0; 202 | while (index < codeChars.length) { 203 | if (codeChars[index] == '/') { 204 | Integer startIndex = -1; 205 | Integer endIndex = -1; 206 | 207 | index++; 208 | if (index >= codeChars.length) 209 | break; 210 | 211 | if (codeChars[index] == '/') { 212 | startIndex = index - 1; 213 | index++; 214 | while (codeChars[index] != '\n') { 215 | index++; 216 | if (index == codeChars.length) { 217 | index--; 218 | break; 219 | } 220 | } 221 | endIndex = index; 222 | index++; 223 | } else if (codeChars[index] == '*') { 224 | startIndex = index - 1; 225 | index++; 226 | 227 | try { 228 | boolean done = false; 229 | while (!done) { 230 | if (codeChars[index] == '*') { 231 | index++; 232 | if (codeChars[index] == '/') { 233 | done = true; 234 | endIndex = index; 235 | } 236 | } 237 | index++; 238 | } 239 | } catch (ArrayIndexOutOfBoundsException e) { 240 | endIndex = codeChars.length - 1; 241 | } 242 | } 243 | 244 | /* if we found stuff add to array */ 245 | if (startIndex != -1) 246 | commentIndexes.add(new Integer[] { startIndex, endIndex }); 247 | } else if (codeChars[index] == '"') { 248 | Integer startIndex = index; 249 | Integer endIndex = -1; 250 | index++; 251 | 252 | try { 253 | while (codeChars[index] != '"') { 254 | if (codeChars[index] == '\\') { 255 | index++; 256 | } 257 | index++; 258 | } 259 | endIndex = index; 260 | index++; 261 | } catch (ArrayIndexOutOfBoundsException e) { 262 | } 263 | 264 | /* add to array */ 265 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 266 | } else if (codeChars[index] == '\'') { 267 | Integer startIndex = index; 268 | Integer endIndex = -1; 269 | index++; 270 | 271 | try { 272 | while (codeChars[index] != '\'') { 273 | if (codeChars[index] == '\\') { 274 | index++; 275 | } 276 | index++; 277 | } 278 | endIndex = index; 279 | index++; 280 | } catch (ArrayIndexOutOfBoundsException e) { 281 | } 282 | 283 | /* add to array */ 284 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 285 | } else { 286 | index++; 287 | } 288 | } 289 | 290 | /* put our two lists inside of a third list */ 291 | finalValues.add(commentIndexes); 292 | finalValues.add(literalIndexes); 293 | 294 | /* return our final list */ 295 | return finalValues; 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /src/main/java/com/automation/javauto/debugger/SimpleDebugger.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.debugger; 2 | 3 | import java.util.ArrayList; 4 | import java.util.regex.*; 5 | import java.util.Collections; 6 | import java.io.*; 7 | 8 | import com.automation.javauto.parser.Create; 9 | 10 | /** 11 | * Takes Java code and does a preliminary debugging to make sure things are 12 | * ready to be compiled. 13 | * 14 | * @author matthew.downey 15 | * 16 | */ 17 | public class SimpleDebugger { 18 | 19 | /* list to hold errors */ 20 | private static ArrayList errors = new ArrayList(); 21 | private static ArrayList errorLines = new ArrayList(); 22 | 23 | private static String userCodeFileName = ""; 24 | private static String javautoFile = "Javauto.java"; 25 | 26 | public static void main(String[] args) { 27 | String userCode = fileRead("thisHasErrors.ja"); 28 | debug(userCode, "thisHasErrors.ja"); 29 | } 30 | 31 | /** 32 | * Does some simple debugging of a user code file. 33 | * 34 | * @param userCode 35 | * the user code to debug 36 | * @return true only if there are no errors, false otherwise 37 | */ 38 | public static boolean debug(String userCode, String fileName) { 39 | /* 40 | * set the global file name so errors can be specific about where an 41 | * error happens 42 | */ 43 | userCodeFileName = fileName; 44 | 45 | /* 46 | * build ignore lists for the data -- this step also handles unclosed 47 | * String literals, character literals, and comments. 48 | */ 49 | ArrayList commentIgnores = getIgnoreIndexes(userCode).get(0); 50 | 51 | /* get rid of all the comments */ 52 | String t = ""; 53 | for (int i = 0; i < userCode.length(); i++) { 54 | if (!inIgnoredText(i, commentIgnores)) 55 | t = t + userCode.substring(i, i + 1); 56 | } 57 | 58 | userCode = t; 59 | 60 | /* build a list of literal ignores */ 61 | ArrayList allIgnores = getIgnoreIndexes(userCode).get(1); 62 | 63 | /* we're gonna need a character array and a line array */ 64 | char[] userChars = userCode.toCharArray(); 65 | String[] userLines = userCode.split("\n"); 66 | 67 | /* first we check to make sure every { has a close } */ 68 | for (int i = 0; i < userChars.length; i++) { 69 | if (userChars[i] == '{' && !inIgnoredText(i, allIgnores)) { 70 | findEndBracket(i, userCode, allIgnores); 71 | } 72 | } 73 | 74 | /* now make sure every } has a { */ 75 | for (int i = userChars.length - 1; i >= 0; i--) { 76 | if (userChars[i] == '}' && !inIgnoredText(i, allIgnores)) { 77 | findStartBracket(i, userCode, allIgnores); 78 | } 79 | } 80 | 81 | /* make sure every line with a ( has a corresponding ) */ 82 | for (int l = 0; l < userLines.length; l++) { 83 | /* use these indexes to populate a list of general ignore indexes */ 84 | ArrayList allIgs = getIgnoreIndexes(userLines[l]).get(1); 85 | 86 | char[] lineChars = userLines[l].toCharArray(); 87 | 88 | /* make sure each ( has a ) */ 89 | for (int i = 0; i < lineChars.length; i++) { 90 | if (lineChars[i] == '(' && !inIgnoredText(i, allIgs)) { 91 | findEndParen(i, userLines[l], allIgs, l); 92 | } 93 | 94 | if (lineChars[i] == ')' && !inIgnoredText(i, allIgs)) { 95 | findStartParen(i, userLines[l], allIgs, l); 96 | } 97 | } 98 | } 99 | 100 | /* make sure string replacements are all right */ 101 | checkStringReplaceFormat(userCode); 102 | 103 | /* make sure any javauto functions/constants are in the right case */ 104 | checkJavautoCase(userCode, allIgnores); 105 | 106 | /* make sure the user doesn't try to override a built in function */ 107 | checkFunctionDeclarations(userCode, allIgnores); 108 | 109 | /* make sure the user doesn't override a javauto variable */ 110 | checkVariableDeclarations(userCode, allIgnores); 111 | 112 | /* if there are no errors return true */ 113 | if (errors.size() == 0) 114 | return false; 115 | 116 | /* remove duplicate line numbers from errorLines */ 117 | ArrayList temp = new ArrayList(); 118 | temp.addAll(errorLines); 119 | errorLines = new ArrayList(); 120 | for (Integer j : temp) 121 | if (!errorLines.contains(j)) 122 | errorLines.add(j); 123 | 124 | /* at the end we display the errors in order of line number */ 125 | Collections.sort(errorLines); 126 | for (int el : errorLines) { 127 | for (String[] e : errors) { 128 | if (el == Integer.parseInt(e[0])) 129 | System.out.println(e[1] + "\n"); 130 | } 131 | } 132 | 133 | /* show how many errors */ 134 | int errorCount = errors.size(); 135 | if (errorCount == 1) 136 | System.out.println(errors.size() + " error."); 137 | else 138 | System.out.println(errors.size() + " errors."); 139 | 140 | return true; 141 | } 142 | 143 | /** 144 | * Find the line that a character appears on based on the character 145 | * position. 146 | * 147 | * @param pos 148 | * the position of the character 149 | * @param generatedCode 150 | * the string the character position is in 151 | * @return the line number containing the character 152 | */ 153 | private static int getLineNumber(int pos, String generatedCode) { 154 | int line = 1; 155 | char[] genChars = generatedCode.toCharArray(); 156 | for (int i = 0; i < pos; i++) 157 | if (genChars[i] == '\n') 158 | line++; 159 | return line; 160 | } 161 | 162 | /** 163 | * Make sure the python file String replacement is formatted like: String s 164 | * = "Hello, my name is %s" % ("John") with the parenthesis after the % 165 | * 166 | * @param userCode 167 | * the code we're auditing 168 | */ 169 | private static void checkStringReplaceFormat(String userCode) { 170 | /* regex to find bad replacements */ 171 | String regexp = "\".*\"\\s*%\\s+"; 172 | Pattern pattern = Pattern.compile(regexp); 173 | Matcher matcher = pattern.matcher(userCode); 174 | 175 | while (matcher.find()) { 176 | /* get the next char that's supposed to be a ( */ 177 | int end = matcher.end(); 178 | String nextChar = userCode.substring(end, end + 1); 179 | 180 | /* add an error if it isn't a ( */ 181 | if (!nextChar.equals("(")) { 182 | int lineNum = getLineNumber(end, userCode); 183 | errorLines.add(lineNum); 184 | String message = "Error in " 185 | + userCodeFileName 186 | + " line " 187 | + lineNum 188 | + "\n" 189 | + "\t" 190 | + userCode.split("\n")[lineNum - 1] 191 | + "\n" 192 | + "Expected a ( after the %.\nLike \"Hello %s\" % (\"John\")"; 193 | errors.add(new String[] { String.valueOf(lineNum), message }); 194 | 195 | } 196 | } 197 | 198 | } 199 | 200 | private static void checkVariableDeclarations(String userCode, 201 | ArrayList allIgnores) { 202 | ArrayList vars = getVariables(); 203 | ArrayList lowerVars = new ArrayList(); 204 | for (String s : vars) 205 | lowerVars.add(s.toLowerCase()); 206 | 207 | String[] lines = userCode.split("\n"); 208 | for (int i = 0; i < lines.length; i++) { 209 | /* regex to search for variable declaration */ 210 | String regexp = "^\\s*[\\S+\\s+]*\\s+(\\w+)\\s*=|^\\s*(\\w+)\\s*="; 211 | Pattern pattern = Pattern.compile(regexp); 212 | Matcher matcher = pattern.matcher(lines[i]); 213 | 214 | while (matcher.find()) { 215 | String found = matcher.group(1); 216 | 217 | /* if it's not part of the first half it's the second */ 218 | if (found == null) 219 | found = matcher.group(2); 220 | 221 | if (lowerVars.contains(found.toLowerCase()) 222 | || found.toLowerCase().equals("args")) { 223 | errorLines.add(i + 1); 224 | String message = "Error in " + userCodeFileName + " line " 225 | + (i + 1) + "\n" + "\t" + userCode.split("\n")[i] 226 | + "\n" + "Cannot override \"" + found 227 | + "\", use a different name."; 228 | errors.add(new String[] { String.valueOf(i + 1), message }); 229 | } 230 | } 231 | 232 | } 233 | 234 | } 235 | 236 | private static void checkFunctionDeclarations(String userCode, 237 | ArrayList allIgnores) { 238 | ArrayList funcs = getFunctions(); 239 | ArrayList lowerFuncs = new ArrayList(); 240 | for (String s : funcs) 241 | lowerFuncs.add(s.toLowerCase()); 242 | 243 | String[] lines = userCode.split("\n"); 244 | for (int i = 0; i < lines.length; i++) { 245 | /* regex to search for function declaration */ 246 | String regexp = "^\\s*func[\\s+\\w+]+\\s(\\w+)\\s*\\("; 247 | Pattern pattern = Pattern.compile(regexp); 248 | Matcher matcher = pattern.matcher(lines[i]); 249 | 250 | while (matcher.find()) { 251 | String found = matcher.group(1); 252 | if (lowerFuncs.contains(found.toLowerCase())) { 253 | errorLines.add(i + 1); 254 | String message = "Error in " 255 | + userCodeFileName 256 | + " line " 257 | + (i + 1) 258 | + "\n" 259 | + "\t" 260 | + userCode.split("\n")[i] 261 | + "\n" 262 | + "Cannot override this function, use a different name."; 263 | errors.add(new String[] { String.valueOf(i + 1), message }); 264 | } 265 | } 266 | } 267 | } 268 | 269 | private static void checkJavautoCase(String userCode, 270 | ArrayList allIgnores) { 271 | ArrayList funcs = getJavauto(); 272 | for (String s : funcs) { 273 | 274 | /* regex to search for function s within code */ 275 | String regexp = "(?i)([^a-zA-Z0-9]+)(" + s + ")([^a-zA-Z0-9]+)"; 276 | Pattern pattern = Pattern.compile(regexp); 277 | Matcher matcher = pattern.matcher(userCode); 278 | 279 | while (matcher.find()) { 280 | String foundFunc = matcher.group(2); 281 | int index = matcher.start() + matcher.group(1).length(); 282 | if (!foundFunc.equals(s) 283 | && foundFunc.toLowerCase().equals(s.toLowerCase()) 284 | && !inIgnoredText(index, allIgnores)) { 285 | int lineNum = getLineNumber(index, userCode); 286 | errorLines.add(lineNum); 287 | String message = "Error in " + userCodeFileName + " line " 288 | + lineNum + "\n" + "\t" 289 | + userCode.split("\n")[lineNum - 1] + "\n" 290 | + "Case of \"" + foundFunc 291 | + "\" is incorrect, it should be \"" + s + "\"."; 292 | errors.add(new String[] { String.valueOf(lineNum), message }); 293 | } 294 | } 295 | 296 | /* 297 | * do the whole regex again looking for func at the beginning of 298 | * file 299 | */ 300 | regexp = "(?i)^(" + s + ")[^a-zA-Z0-9]+"; 301 | pattern = Pattern.compile(regexp); 302 | matcher = pattern.matcher(userCode); 303 | 304 | while (matcher.find()) { 305 | String foundFunc = matcher.group(1); 306 | if (!foundFunc.equals(s) 307 | && foundFunc.toLowerCase().equals(s.toLowerCase())) { 308 | int lineNum = 1; 309 | errorLines.add(lineNum); 310 | String message = "Error in " + userCodeFileName + " line " 311 | + lineNum + "\n" + "\t" 312 | + userCode.split("\n")[lineNum - 1] + "\n" 313 | + "Case of \"" + foundFunc 314 | + "\" is incorrect, it should be \"" + s + "\"."; 315 | errors.add(new String[] { String.valueOf(lineNum), message }); 316 | } 317 | } 318 | } 319 | } 320 | 321 | /** 322 | * Search the javautoFile for all class variables and return them 323 | * 324 | * @return class variables that have been generated 325 | */ 326 | private static ArrayList getVariables() { 327 | /* get raw file contents of the file containing our variables */ 328 | String[] variablesContents = resourceRead(javautoFile).split("\n"); 329 | 330 | /* variable to store our generated class vars */ 331 | ArrayList classVars = new ArrayList(); 332 | 333 | /* add each line that has a class varaible to our classVars */ 334 | for (String line : variablesContents) { 335 | if ((line.trim().startsWith("public ") || line.trim().startsWith( 336 | "private ")) 337 | && line.trim().endsWith(";")) { 338 | String[] parts = line.split("=")[0].split(" "); 339 | String name = parts[parts.length - 1].trim(); 340 | classVars.add(name); 341 | } 342 | } 343 | 344 | /* return our class vars */ 345 | return classVars; 346 | } 347 | 348 | /** 349 | * Gets a list of functions and their source code from the javautoFile 350 | */ 351 | private static ArrayList getFunctions() { 352 | /* define the list where we'll store all the data */ 353 | ArrayList functionDataList = new ArrayList(); 354 | 355 | /* get raw file contents of the file containing our functions */ 356 | String functionContents = resourceRead(javautoFile); 357 | 358 | /* split into lines for evaluation */ 359 | String[] functionContentsLines = functionContents.split("\n"); 360 | 361 | /* check each line and extract function names */ 362 | for (String line : functionContentsLines) { 363 | /* 364 | * if the line is like "public *{" or "private *{" but isn't like 365 | * "public class" 366 | */ 367 | if ((line.trim().startsWith("public ") || line.trim().startsWith( 368 | "private ")) 369 | && (line.trim().endsWith("{")) 370 | && (!line.trim().startsWith("public class"))) { 371 | /* 372 | * if it meets the above criteria it's a function & we add it to 373 | * the list 374 | */ 375 | 376 | /* get function name & code */ 377 | String functionName = line.trim().split(" ")[2].split("[(]")[0]; 378 | 379 | /* 380 | * add it to the list unless it's the "run" function used in a 381 | * thread 382 | */ 383 | if (!functionName.toLowerCase().equals("run") 384 | && !functionDataList.contains(functionName.trim())) { 385 | functionDataList.add(functionName.trim()); 386 | } 387 | } 388 | } 389 | 390 | /* return our list without duplicates */ 391 | return functionDataList; 392 | } 393 | 394 | private static ArrayList getJavauto() { 395 | /* define the list where we'll store all the data */ 396 | ArrayList functionDataList = new ArrayList(); 397 | 398 | /* get raw file contents of the file containing our functions */ 399 | String functionContents = resourceRead(javautoFile); 400 | 401 | /* split into lines for evaluation */ 402 | String[] functionContentsLines = functionContents.split("\n"); 403 | 404 | /* check each line and extract function names */ 405 | for (String line : functionContentsLines) { 406 | /* 407 | * if the line is like "public *{" or "private *{" but isn't like 408 | * "public class" 409 | */ 410 | if ((line.trim().startsWith("public ") || line.trim().startsWith( 411 | "private ")) 412 | && (line.trim().endsWith("{")) 413 | && (!line.trim().startsWith("public class"))) { 414 | /* 415 | * if it meets the above criteria it's a function & we add it to 416 | * the list 417 | */ 418 | 419 | /* get function name & code */ 420 | String functionName = line.trim().split(" ")[2].split("[(]")[0]; 421 | 422 | /* 423 | * add it to the list unless it's the "run" function used in a 424 | * thread 425 | */ 426 | if (!functionName.toLowerCase().equals("run")) { 427 | String function = functionName.trim(); 428 | if (!functionDataList.contains(function)) 429 | functionDataList.add(function); 430 | } 431 | } 432 | 433 | /* if it's a variable */ 434 | else if ((line.trim().startsWith("public ") || line.trim() 435 | .startsWith("private ")) && line.trim().endsWith(";")) { 436 | String[] parts = line.split("=")[0].split(" "); 437 | String name = parts[parts.length - 1].trim(); 438 | functionDataList.add(name); 439 | } 440 | } 441 | 442 | /* return our list without duplicates */ 443 | return functionDataList; 444 | } 445 | 446 | /** 447 | * Reads file contents (from a resource inside the JAR) into string 448 | * 449 | * @param resourcePath 450 | * the path to the resource within the JAR file 451 | * @return file contents as string 452 | */ 453 | private static String resourceRead(String resourcePath) { 454 | try { 455 | InputStream inputStream = Thread.currentThread() 456 | .getContextClassLoader().getResourceAsStream(resourcePath); 457 | 458 | BufferedReader bufferedReader = new BufferedReader( 459 | new InputStreamReader(inputStream, "UTF-8")); 460 | StringBuilder stringBuilder = new StringBuilder(); 461 | String line = bufferedReader.readLine(); 462 | while (line != null) { 463 | stringBuilder.append(line); 464 | if (line != null) { 465 | stringBuilder.append("\n"); 466 | } 467 | line = bufferedReader.readLine(); 468 | } 469 | return stringBuilder.toString(); 470 | } catch (Exception e) { 471 | System.out 472 | .println("Compiler encountered an error reading JAR resource \"" 473 | + resourcePath 474 | + "\" -- the JAR file may be corrupt."); 475 | e.printStackTrace(); 476 | System.exit(1); 477 | return ""; 478 | } 479 | } 480 | 481 | /** 482 | * Reads file contents into a string 483 | * 484 | * @param filePath 485 | * path of file to read 486 | * @return file contents as string 487 | */ 488 | private static String fileRead(String filePath) { 489 | try { 490 | BufferedReader br = new BufferedReader(new FileReader(filePath)); 491 | StringBuilder data = new StringBuilder(); 492 | String line = br.readLine(); 493 | while (line != null) { 494 | data.append(line); 495 | data.append('\n'); 496 | line = br.readLine(); 497 | } 498 | String fileData = data.toString(); 499 | br.close(); 500 | return fileData; 501 | } catch (Exception e) { 502 | System.out.println("Compiler encountered an error reading file \"" 503 | + filePath + "\""); 504 | e.printStackTrace(); 505 | System.exit(1); 506 | return "null"; 507 | } 508 | } 509 | 510 | /** 511 | * Given the index of a '{', find the corresponding '}'. 512 | * 513 | * @param startBracket 514 | * the index of the '{'. 515 | * @param context 516 | * the string within which the parens are located. 517 | * @param indexesToIgnore 518 | * A list of Integers like [start, end] that specify indexes that 519 | * should be ignored, this list usually contains the start and 520 | * end bounds of each comment and string literal in the context. 521 | * @return the index of the closing paren 522 | */ 523 | private static int findEndBracket(int startBracket, String context, 524 | ArrayList indexesToIgnore) { 525 | char[] contextChars = context.toCharArray(); 526 | int index = startBracket + 1; 527 | int open = 1; 528 | int close = 0; 529 | try { 530 | while (open > close) { 531 | /* 532 | * if the current character is a ( and it's not inside a comment 533 | * or literal 534 | */ 535 | if (contextChars[index] == '{' 536 | && !inIgnoredText(index, indexesToIgnore)) { 537 | open++; 538 | } 539 | /* 540 | * if the current character is a ) and it's not inside a comment 541 | * or literal 542 | */ 543 | else if (contextChars[index] == '}' 544 | && !inIgnoredText(index, indexesToIgnore)) { 545 | close++; 546 | } 547 | /* on to the next one */ 548 | index++; 549 | } 550 | } catch (ArrayIndexOutOfBoundsException e) { 551 | int lineNum = getLineNumber(startBracket, context); 552 | errorLines.add(lineNum); 553 | String message = "Error in " + userCodeFileName + " line " 554 | + lineNum + "\n" + "\t" + context.split("\n")[lineNum - 1] 555 | + "\n" + "Expected corresponding '}'"; 556 | errors.add(new String[] { String.valueOf(lineNum), message }); 557 | } 558 | return index; 559 | } 560 | 561 | private static int findStartBracket(int endBracket, String context, 562 | ArrayList indexesToIgnore) { 563 | char[] contextChars = context.toCharArray(); 564 | int index = endBracket - 1; 565 | int open = 0; 566 | int close = 1; 567 | try { 568 | while (close > open) { 569 | /* 570 | * if the current character is a ( and it's not inside a comment 571 | * or literal 572 | */ 573 | if (contextChars[index] == '{' 574 | && !inIgnoredText(index, indexesToIgnore)) { 575 | open++; 576 | } 577 | /* 578 | * if the current character is a ) and it's not inside a comment 579 | * or literal 580 | */ 581 | else if (contextChars[index] == '}' 582 | && !inIgnoredText(index, indexesToIgnore)) { 583 | close++; 584 | } 585 | /* on to the next one */ 586 | index--; 587 | } 588 | } catch (ArrayIndexOutOfBoundsException e) { 589 | int lineNum = getLineNumber(endBracket, context); 590 | errorLines.add(lineNum); 591 | String message = "Error in " + userCodeFileName + " line " 592 | + lineNum + "\n" + "\t" + context.split("\n")[lineNum - 1] 593 | + "\n" + "Unexpected '}'"; 594 | errors.add(new String[] { String.valueOf(lineNum), message }); 595 | } 596 | return index; 597 | } 598 | 599 | /** 600 | * Given the index of a '(', find the corresponding ')'. 601 | * 602 | * @param startParen 603 | * the index of the '('. 604 | * @param context 605 | * the string within which the parens are located. 606 | * @param indexesToIgnore 607 | * A list of Integers like [start, end] that specify indexes that 608 | * should be ignored, this list usually contains the start and 609 | * end bounds of each comment and string literal in the context. 610 | * @return the index of the closing paren 611 | */ 612 | private static int findEndParen(int startParen, String context, 613 | ArrayList indexesToIgnore, int lineNumber) { 614 | char[] contextChars = context.toCharArray(); 615 | int index = startParen + 1; 616 | int open = 1; 617 | int close = 0; 618 | try { 619 | while (open > close) { 620 | /* 621 | * if the current character is a ( and it's not inside a comment 622 | * or literal 623 | */ 624 | if (contextChars[index] == '(' 625 | && !inIgnoredText(index, indexesToIgnore)) { 626 | open++; 627 | } 628 | /* 629 | * if the current character is a ) and it's not inside a comment 630 | * or literal 631 | */ 632 | else if (contextChars[index] == ')' 633 | && !inIgnoredText(index, indexesToIgnore)) { 634 | close++; 635 | } 636 | /* on to the next one */ 637 | index++; 638 | } 639 | } catch (ArrayIndexOutOfBoundsException e) { 640 | errorLines.add(lineNumber); 641 | String message = "Error in " + userCodeFileName + " line " 642 | + (lineNumber + 1) + "\n" + "\t" + context + "\n" 643 | + "Unclosed '(', expected corresponding ')'"; 644 | errors.add(new String[] { String.valueOf(lineNumber), message }); 645 | } 646 | return index; 647 | } 648 | 649 | private static int findStartParen(int endParen, String context, 650 | ArrayList indexesToIgnore, int lineNumber) { 651 | char[] contextChars = context.toCharArray(); 652 | int index = endParen - 1; 653 | int open = 0; 654 | int close = 1; 655 | try { 656 | while (close > open) { 657 | /* 658 | * if the current character is a ( and it's not inside a comment 659 | * or literal 660 | */ 661 | if (contextChars[index] == '(' 662 | && !inIgnoredText(index, indexesToIgnore)) { 663 | open++; 664 | } 665 | /* 666 | * if the current character is a ) and it's not inside a comment 667 | * or literal 668 | */ 669 | else if (contextChars[index] == ')' 670 | && !inIgnoredText(index, indexesToIgnore)) { 671 | close++; 672 | } 673 | /* on to the next one */ 674 | index--; 675 | } 676 | } catch (ArrayIndexOutOfBoundsException e) { 677 | errorLines.add(lineNumber); 678 | String message = "Error in " + userCodeFileName + " line " 679 | + (lineNumber + 1) + "\n" + "\t" + context + "\n" 680 | + "Unexpected ')'"; 681 | errors.add(new String[] { String.valueOf(lineNumber), message }); 682 | } 683 | return index; 684 | } 685 | 686 | /** 687 | * Determines if a character is inside any of the bounds of a list of blocks 688 | * of text to ignore. 689 | * 690 | * @param charIndex 691 | * the index of the character whose position is being checked 692 | * @param ignoredIndex 693 | * a list of items like [int startIgnoreIndex, int 694 | * endIgnoreIndex] that specifies which indexes are supposed to 695 | * be ignored 696 | * @return returns true if the character index is within any of the ignore 697 | * bounds, otherwise returns false. 698 | */ 699 | private static boolean inIgnoredText(int charIndex, 700 | ArrayList ignoredIndexes) { 701 | /* check each set of bounds to see if they hold our charIndex */ 702 | for (Integer[] i : ignoredIndexes) { 703 | if (charIndex >= i[0] && charIndex <= i[1]) 704 | return true; 705 | } 706 | 707 | /* if we got to here we haven't found it inside any of the bounds */ 708 | return false; 709 | } 710 | 711 | /** 712 | * Build a list of character indexes that should be ignored during 713 | * processing. Characters to be ignored are those inside of comments, string 714 | * literals, and character literals. This function returns the bounds of 715 | * indexes of characters and literals in two separate lists. 716 | * 717 | * @param code 718 | * the string to generate this list of bounds for 719 | * @return returns two ArrayList objects, wrapped inside of one 720 | * ArrayList, with the format [comment indexes, literal indexes]. 721 | * Then each of those elements is a list with the format [start 722 | * ignore index, end ignore index]. 723 | */ 724 | private static ArrayList> getIgnoreIndexes(String code) { 725 | /* Lists to hold bounds for both comments and literals */ 726 | ArrayList commentIndexes = new ArrayList(); 727 | ArrayList literalIndexes = new ArrayList(); 728 | 729 | /* 730 | * List to hold our other two lists, so that the user can separate them 731 | * at will 732 | */ 733 | ArrayList> finalValues = new ArrayList>(); 734 | 735 | /* 736 | * iterate through character by character looking for comments and 737 | * literals 738 | */ 739 | char[] codeChars = code.toCharArray(); 740 | int index = 0; 741 | while (index < codeChars.length) { 742 | if (codeChars[index] == '/') { 743 | Integer startIndex = -1; 744 | Integer endIndex = -1; 745 | 746 | index++; 747 | 748 | if (codeChars[index] == '/') { 749 | startIndex = index - 1; 750 | index++; 751 | while (codeChars[index] != '\n') { 752 | index++; 753 | if (index == codeChars.length) { 754 | index--; 755 | break; 756 | } 757 | } 758 | endIndex = index - 1; 759 | index++; 760 | } else if (codeChars[index] == '*') { 761 | startIndex = index - 1; 762 | index++; 763 | 764 | try { 765 | boolean done = false; 766 | while (!done) { 767 | if (codeChars[index] == '*') { 768 | index++; 769 | if (codeChars[index] == '/') { 770 | done = true; 771 | endIndex = index; 772 | } 773 | } 774 | index++; 775 | } 776 | } catch (ArrayIndexOutOfBoundsException e) { 777 | int lineNum = getLineNumber(startIndex, code); 778 | errorLines.add(lineNum); 779 | 780 | String message = "Error in " + userCodeFileName 781 | + " line " + lineNum + "\n" + "\t" 782 | + code.split("\n")[lineNum - 1] + "\n" 783 | + "Unclosed comment."; 784 | errors.add(new String[] { String.valueOf(lineNum), 785 | message }); 786 | } 787 | } 788 | 789 | /* if we found stuff add to array */ 790 | if (startIndex != -1) 791 | commentIndexes.add(new Integer[] { startIndex, endIndex }); 792 | } else if (codeChars[index] == '"') { 793 | Integer startIndex = index; 794 | Integer endIndex = -1; 795 | index++; 796 | 797 | try { 798 | while (codeChars[index] != '"') { 799 | if (codeChars[index] == '\\') { 800 | index++; 801 | } 802 | index++; 803 | } 804 | endIndex = index; 805 | index++; 806 | } catch (ArrayIndexOutOfBoundsException e) { 807 | int lineNum = getLineNumber(startIndex, code); 808 | errorLines.add(lineNum); 809 | 810 | String message = "Error in " + userCodeFileName + " line " 811 | + lineNum + "\n" + "\t" 812 | + code.split("\n")[lineNum - 1] + "\n" 813 | + "Unclosed string literal."; 814 | errors.add(new String[] { String.valueOf(lineNum), message }); 815 | } 816 | 817 | /* add to array */ 818 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 819 | } else if (codeChars[index] == '\'') { 820 | Integer startIndex = index; 821 | Integer endIndex = -1; 822 | index++; 823 | 824 | try { 825 | while (codeChars[index] != '\'') { 826 | if (codeChars[index] == '\\') { 827 | index++; 828 | } 829 | index++; 830 | } 831 | endIndex = index; 832 | index++; 833 | } catch (ArrayIndexOutOfBoundsException e) { 834 | int lineNum = getLineNumber(startIndex, code); 835 | errorLines.add(lineNum); 836 | 837 | String message = "Error in " + userCodeFileName + " line " 838 | + lineNum + "\n" + "\t" 839 | + code.split("\n")[lineNum - 1] + "\n" 840 | + "Unclosed character literal."; 841 | errors.add(new String[] { String.valueOf(lineNum), message }); 842 | } 843 | 844 | /* add to array */ 845 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 846 | } else { 847 | index++; 848 | } 849 | } 850 | 851 | /* put our two lists inside of a third list */ 852 | finalValues.add(commentIndexes); 853 | finalValues.add(literalIndexes); 854 | 855 | /* return our final list */ 856 | return finalValues; 857 | } 858 | } 859 | -------------------------------------------------------------------------------- /src/main/java/com/automation/javauto/parser/Create.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.parser; 2 | 3 | import java.io.*; 4 | import java.util.Locale; 5 | import java.util.List; 6 | import java.util.ArrayList; 7 | import java.util.regex.*; 8 | 9 | import javax.tools.*; 10 | 11 | import com.automation.javauto.compiler.CustomJarCompiler; 12 | import com.automation.javauto.compiler.CustomJavaCompiler; 13 | import com.automation.javauto.debugger.SimpleDebugger; 14 | import com.automation.javauto.compiler.DealWithCompilerErrors; 15 | 16 | /** 17 | * 18 | * This class handles the top level user code parsing. It takes a .ja or 19 | * .javauto file and parses a copy of the Javauto.java file in order to create 20 | * functions, it creates struct objects and class variables, and then it uses 21 | * the {@link SimpleDebugger} class to check its generated code. If everything 22 | * checks out, it runs the code through {@link CustomJavaCompiler} to generate 23 | * class files; any errors at this point are sent directly to 24 | * {@link DealWithCompilerErrors} to be displayed. Finally 25 | * {@link CustomJarCompiler} * is used to bundle the class files into a jar. 26 | * 27 | * @author matthew.downey 28 | * 29 | */ 30 | public class Create { 31 | /* define constants for different terminal colors */ 32 | private static String RED = "\033[91m"; 33 | private static String GREEN = "\033[92m"; 34 | private static String YELLOW = "\033[93m"; 35 | private static String BLUE = "\033[96m"; 36 | private static String NORMAL = "\033[0m"; 37 | 38 | /* controls whether we're in verbose mode */ 39 | private static boolean verbose = false; 40 | 41 | /* controls whether we're generating .java files */ 42 | private static boolean genJava = false; 43 | 44 | /* controls whether we're keeping the generated .class files */ 45 | private static boolean keepClass = false; 46 | 47 | /* the file our javauto functions are located in */ 48 | private static String javautoFile = "Javauto.java"; 49 | 50 | /* used by various functions to determine if they've printed to terminal */ 51 | private static boolean printedResults = false; 52 | 53 | /* if this variable is true we will execute a search and then exit */ 54 | private static boolean doSearch = false; 55 | 56 | /* 57 | * ArrayList to hold our struct objects, which are converted into java 58 | * objects and must be written to a separate file in the same directory. 59 | * Each index should have [struct name, struct code] 60 | */ 61 | private static ArrayList structFiles; 62 | 63 | /* the template used to organize generated code */ 64 | private static String template = "\n" + "\n" 65 | + "\n" + "\n" 66 | + "\n" + "\n" + "\n" 67 | + "<{_*_generatedFunctions_*_}>\n" + ""; 68 | 69 | public static void main(String[] args) { 70 | /* check to see if colors are in use */ 71 | boolean useColors = true; 72 | try { 73 | BufferedReader br = new BufferedReader( 74 | new FileReader("colors.conf")); 75 | StringBuilder data = new StringBuilder(); 76 | String line = br.readLine(); 77 | while (line != null) { 78 | data.append(line); 79 | data.append('\n'); 80 | line = br.readLine(); 81 | } 82 | String fileData = data.toString().trim(); 83 | br.close(); 84 | int c = Integer.parseInt(fileData); 85 | if (c == 0) 86 | useColors = false; 87 | } catch (Exception e) { 88 | } 89 | if (!useColors) { 90 | RED = ""; 91 | GREEN = ""; 92 | YELLOW = ""; 93 | BLUE = ""; 94 | NORMAL = ""; 95 | } 96 | 97 | /* display error if no arguments are provided or if it's just a -v flag */ 98 | if (args.length == 0) { 99 | System.out.println("Usage: javauto "); 100 | System.out.println("Options:"); 101 | System.out.println("\t-v\t--verbose\t\tcompile in verbose mode"); 102 | System.out 103 | .println("\t-g\t--generate\t\tgenerate .java and .class files"); 104 | System.out 105 | .println("\t-gj\t--generate-java\t\tgenerate .java files"); 106 | System.out 107 | .println("\t-gc\t--generate-class\tgenerate .class files"); 108 | } 109 | 110 | /* compile each file provided */ 111 | for (String userCodeFile : args) { 112 | 113 | /* 114 | * initialize the struct files as an empty array for potential user 115 | * structs in this userCodeFile 116 | */ 117 | structFiles = new ArrayList(); 118 | 119 | /* if it's not a file but a no-colors flag */ 120 | if (userCodeFile.equals("-nc") 121 | || userCodeFile.equals("--no-colors")) { 122 | /* set all the colors to empty */ 123 | RED = ""; 124 | GREEN = ""; 125 | YELLOW = ""; 126 | BLUE = ""; 127 | NORMAL = ""; 128 | continue; 129 | } 130 | 131 | /* if it's not a file but a verbose flag */ 132 | if (userCodeFile.equals("-v") || userCodeFile.equals("--verbose")) { 133 | /* set verbose to true and continue with next iteration */ 134 | verbose = true; 135 | continue; 136 | } 137 | 138 | /* if it's not a file but a flag */ 139 | else if (userCodeFile.equals("-g") 140 | || userCodeFile.equals("--generate")) { 141 | /* set keeps to true and continue with next iteration */ 142 | keepClass = true; 143 | genJava = true; 144 | continue; 145 | } 146 | 147 | /* if it's not a file but a flag */ 148 | else if (userCodeFile.equals("-gj") 149 | || userCodeFile.equals("--generate-java")) { 150 | /* set keeps to true and continue with next iteration */ 151 | genJava = true; 152 | continue; 153 | } 154 | 155 | /* if it's not a file but a flag */ 156 | else if (userCodeFile.equals("-gc") 157 | || userCodeFile.equals("--generate-class")) { 158 | /* set keeps to true and continue with next iteration */ 159 | keepClass = true; 160 | continue; 161 | } 162 | 163 | /* check to make sure it's a .javauto file */ 164 | if (!userCodeFile.toLowerCase().endsWith(".javauto") 165 | && !userCodeFile.toLowerCase().endsWith(".ja")) { 166 | System.out.println("Not a .javauto file: " + GREEN 167 | + userCodeFile + NORMAL); 168 | continue; 169 | } 170 | 171 | /* check to make sure the file exists */ 172 | if (!new File(userCodeFile).exists()) { 173 | System.out.println("File not found: " + GREEN + userCodeFile 174 | + NORMAL); 175 | continue; 176 | } 177 | 178 | /* the class name of our main user code */ 179 | String className = new File(userCodeFile).getName().split( 180 | "\\.(?=[^\\.]+$)")[0]; 181 | 182 | verbose("Generating " + GREEN + className + NORMAL + "..."); 183 | 184 | if (!className.matches("^[a-zA-Z].*")) { 185 | System.out.println(RED 186 | + "Error: class names must start with a letter. " 187 | + GREEN + className + RED 188 | + " does not start with a letter." + NORMAL); 189 | System.exit(1); 190 | } 191 | if (!className.matches("^\\S+$")) { 192 | System.out.println(RED 193 | + "Error: class names must not contain spaces. " 194 | + GREEN + className + RED + " contains spaces." 195 | + NORMAL); 196 | System.exit(1); 197 | } 198 | 199 | /* file path of our build folder (currentDir/build) */ 200 | String directory = new File(userCodeFile).getAbsolutePath() 201 | .substring( 202 | 0, 203 | new File(userCodeFile).getAbsolutePath() 204 | .lastIndexOf(File.separator)) 205 | + File.separator + className; 206 | 207 | /* 208 | * if we're not keeping any of the generated files make the dir 209 | * hidden 210 | */ 211 | if (!keepClass && !genJava) 212 | directory = new File(userCodeFile).getAbsolutePath().substring( 213 | 0, 214 | new File(userCodeFile).getAbsolutePath().lastIndexOf( 215 | File.separator)) 216 | + File.separator + "." + className; 217 | 218 | /* 219 | * file path of our gen directory (build/gen) for generated java 220 | * files 221 | */ 222 | String genDirectory = directory + File.separator + "gen"; 223 | 224 | /* 225 | * file path of our class directory (build/class) for our compiled 226 | * .class files 227 | */ 228 | String classDirectory = directory + File.separator + "class"; 229 | 230 | /* get javauto code to compile */ 231 | String javautoCode = fileRead(userCodeFile); 232 | 233 | /* 234 | * perform rudimentary debugging and stop compiling if there's an 235 | * error 236 | */ 237 | boolean err = SimpleDebugger.debug(javautoCode, userCodeFile); 238 | if (err) 239 | System.exit(1); 240 | 241 | /* generate java code from the provided javauto code */ 242 | String generatedCode = generateJavaCode(javautoCode, className); 243 | verbose("Generation complete... starting build"); 244 | 245 | /*** Now the build begins ***/ 246 | 247 | /* create our build folder if it doesn't exist */ 248 | File outDir = new File(directory); 249 | if (!outDir.exists()) { 250 | verbose("Creating directory " + GREEN + directory + NORMAL 251 | + "..."); 252 | if (!outDir.mkdir()) { 253 | System.out 254 | .println("Error: couldn't create build directory " 255 | + GREEN 256 | + directory 257 | + NORMAL 258 | + "\nPlease create this directory manually."); 259 | System.exit(1); 260 | } 261 | } 262 | /* 263 | * if our build folder is temporary and we're on windows hide the 264 | * folder manually 265 | */ 266 | if (!keepClass 267 | && !genJava 268 | && System.getProperty("os.name").toLowerCase() 269 | .contains("windows")) { 270 | String cmd = "Executing cmd /c attrib +s +h \"" + directory 271 | + "\"..."; 272 | verbose(cmd); 273 | try { 274 | Process p = Runtime.getRuntime().exec( 275 | "cmd /c attrib +s +h \"" + directory + "\""); 276 | } catch (Exception e) { 277 | verbose(RED + "Failed." + NORMAL); 278 | } 279 | } 280 | 281 | /* create our gen folder if it doesn't exist */ 282 | if (genJava) { 283 | outDir = new File(genDirectory); 284 | if (!outDir.exists()) { 285 | verbose("Creating directory " + GREEN + genDirectory 286 | + NORMAL + "..."); 287 | if (!outDir.mkdir()) { 288 | System.out 289 | .println("Error: couldn't create gen directory " 290 | + GREEN 291 | + genDirectory 292 | + NORMAL 293 | + "\nPlease create this directory manually."); 294 | System.exit(1); 295 | } 296 | } 297 | } 298 | 299 | /* create our class folder if it doesn't exist */ 300 | outDir = new File(classDirectory); 301 | if (!outDir.exists()) { 302 | verbose("Creating directory " + GREEN + classDirectory + NORMAL 303 | + "..."); 304 | if (!outDir.mkdir()) { 305 | System.out 306 | .println("Error: couldn't create class directory " 307 | + GREEN 308 | + classDirectory 309 | + NORMAL 310 | + "\nPlease create this directory manually."); 311 | System.exit(1); 312 | } 313 | } 314 | 315 | if (genJava) { 316 | /* build all of our user struct files */ 317 | for (String[] structFile : structFiles) { 318 | String outPath = genDirectory + File.separator 319 | + structFile[0] + ".java"; 320 | verbose("Building " + GREEN + outPath + NORMAL + "..."); 321 | fileWrite(outPath, structFile[1] + "\n"); 322 | } 323 | } 324 | 325 | if (genJava) { 326 | /* build our main file */ 327 | String outputFile = genDirectory + File.separator + className 328 | + ".java"; 329 | verbose("Building " + GREEN + outputFile + NORMAL + "..."); 330 | fileWrite(outputFile, generatedCode); 331 | } 332 | 333 | /*** Now it's time to generate class files ***/ 334 | 335 | /* first generate each struct */ 336 | for (String[] structFile : structFiles) { 337 | verbose("Building " + GREEN + classDirectory + File.separator 338 | + structFile[0] + ".class" + NORMAL + "..."); 339 | 340 | /* 341 | * use our custom compiler {@link CustomJavaCompiler} to attempt 342 | * to compile the file, if it doesn't work out errors will be 343 | * stored in the DiagnosticCollector 344 | */ 345 | DiagnosticCollector compileErrors = null; 346 | try { 347 | compileErrors = CustomJavaCompiler.compile(structFile[0], 348 | structFile[1], classDirectory, classDirectory); 349 | } catch (IOException ioe) { 350 | System.out.println(RED 351 | + "Error: couldn't write to file in directory " 352 | + classDirectory + NORMAL); 353 | ioe.printStackTrace(); 354 | } 355 | 356 | /* if there is an error */ 357 | if (compileErrors != null) { 358 | 359 | /* iterate through each error */ 360 | for (Diagnostic diagnostic : compileErrors.getDiagnostics()) { 361 | 362 | /* 363 | * find the struct in the user code that is causing the 364 | * issue 365 | */ 366 | String[] javautoCodeLines = javautoCode.split("\n"); 367 | int structlinenum = -1; 368 | for (int k = 0; k < javautoCodeLines.length; k++) { 369 | if (removeLiterals( 370 | removeComments(javautoCodeLines[k])).trim() 371 | .startsWith("struct " + structFile[0])) 372 | structlinenum = k; 373 | } 374 | 375 | /* if we found the struct declaration include that */ 376 | if (structlinenum == -1) 377 | /* print the error message */ 378 | System.out.println(diagnostic.getKind().toString() 379 | .toLowerCase() 380 | + " in struct " + structFile[0] + ":"); 381 | else 382 | /* print the error message */ 383 | System.out.println(diagnostic.getKind() 384 | + " in struct declaration for " 385 | + structFile[0] + " starting on line " 386 | + structlinenum + ":\n\t" 387 | + javautoCodeLines[structlinenum]); 388 | System.out.println(diagnostic.getMessage(Locale 389 | .getDefault()) + "\n"); 390 | } 391 | 392 | /* clean up */ 393 | if (!keepClass && !genJava) { 394 | if (deleteDirectory(new File(directory))) { 395 | verbose("Removed temporary dir " + GREEN 396 | + directory + NORMAL); 397 | } else { 398 | verbose(RED + "Failed to remove temporary dir " 399 | + directory + NORMAL); 400 | } 401 | } 402 | 403 | /* exit because we found an error */ 404 | System.exit(1); 405 | } 406 | } 407 | 408 | /* now compile main user code */ 409 | verbose("Building " + GREEN + classDirectory + File.separator 410 | + className + ".class" + NORMAL + "..."); 411 | 412 | /* 413 | * use our custom compiler {@link CustomJavaCompiler.java} to 414 | * attempt to compile the file, if it doesn't work out errors will 415 | * be stored in the DiagnosticCollector 416 | */ 417 | DiagnosticCollector compileErrors = null; 418 | try { 419 | compileErrors = CustomJavaCompiler.compile(className, 420 | generatedCode, classDirectory, classDirectory); 421 | } catch (IOException ioe) { 422 | System.out.println(RED 423 | + "Error: couldn't write to file in directory " 424 | + classDirectory + NORMAL); 425 | ioe.printStackTrace(); 426 | } 427 | 428 | /* if there is an error */ 429 | if (compileErrors != null) { 430 | 431 | /* 432 | * give the errors to our DealWithCompilerErrors.java to take 433 | * care of 434 | */ 435 | DealWithCompilerErrors.dealWithIt(compileErrors, generatedCode, 436 | javautoCode, userCodeFile); 437 | 438 | /* clean up */ 439 | if (!keepClass && !genJava) { 440 | if (deleteDirectory(new File(directory))) { 441 | verbose("Removed temporary dir " + GREEN + directory 442 | + NORMAL); 443 | } else { 444 | verbose(RED + "Failed to remove temporary dir " 445 | + directory + NORMAL); 446 | } 447 | } 448 | 449 | /* exit because we found an error */ 450 | System.exit(1); 451 | } 452 | 453 | /* now create a .jar file from our class files */ 454 | if (verbose) 455 | CustomJarCompiler.verbose = true; 456 | if (GREEN.equals("")) // if colors are blank 457 | CustomJarCompiler.colors = false; 458 | String jarOut = className + ".jar"; 459 | if (keepClass || genJava) 460 | jarOut = directory + File.separator + className + ".jar"; 461 | 462 | try { 463 | CustomJarCompiler.create(jarOut, className, classDirectory); 464 | } catch (IOException ioe) { 465 | System.out.println(RED + "Error: could not write to file " 466 | + jarOut + NORMAL); 467 | ioe.printStackTrace(); 468 | } finally { 469 | if (!keepClass && !genJava) { 470 | if (deleteDirectory(new File(directory))) { 471 | verbose("Removed temporary dir " + GREEN + directory 472 | + NORMAL); 473 | } else { 474 | verbose(RED + "Failed to remove temporary dir " 475 | + directory + NORMAL); 476 | } 477 | } 478 | } 479 | 480 | /* set our jar file to be executable */ 481 | verbose("Setting executable permissions for " + GREEN + jarOut 482 | + NORMAL + "..."); 483 | File ourJar = new File(jarOut); 484 | ourJar.setExecutable(true); 485 | 486 | /* we're done compiling */ 487 | verbose("Operation complete."); 488 | 489 | } 490 | 491 | } 492 | 493 | /** 494 | * Highlight a term inside of a string. 495 | * 496 | * @param term 497 | * the term to highlight (ingores anything thats not a letter or 498 | * number) 499 | * @param context 500 | * the string in which the term is found and highlighted 501 | * @param startHighlight 502 | * the chracter to use to "highlight" the beginning 503 | * @param endHighlight 504 | * the character to end the highlighting with 505 | * @return the highlighted string 506 | */ 507 | private static String highlight(String term, String context, 508 | String startHighlight, String endHighlight) { 509 | /* 510 | * convert to lower case and replace non word characters with spaces so 511 | * that indexes remain the same 512 | */ 513 | String indexedCon = context.replaceAll("[^a-zA-Z0-9]", " ") 514 | .toLowerCase(); 515 | 516 | /* get our term without non words */ 517 | String stripTerm = term.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); 518 | 519 | /* build a regex to find the starting and ending indexes of our term */ 520 | String regexp = ""; 521 | String[] termParts = stripTerm.split(""); 522 | for (int i = 1; i < termParts.length; i++) { 523 | regexp = regexp + termParts[i] + "\\s*"; 524 | } 525 | regexp = regexp.substring(0, regexp.length() - 3); 526 | 527 | /* search for our pattern in the string */ 528 | Pattern pattern = Pattern.compile(regexp); 529 | Matcher matcher = pattern.matcher(indexedCon); 530 | 531 | /* get start and end indexes of our term inside the string */ 532 | ArrayList startEnd = new ArrayList(); 533 | while (matcher.find()) 534 | startEnd.add(new Integer[] { matcher.start(), matcher.end() }); 535 | 536 | /* craft our highlighted result */ 537 | int shiftLen = 0; 538 | String res = context; 539 | for (Integer[] coords : startEnd) { 540 | int start = coords[0] + shiftLen; 541 | int end = coords[1] + shiftLen; 542 | res = res.substring(0, start) + startHighlight 543 | + res.substring(start, end) + endHighlight 544 | + res.substring(end, res.length()); 545 | shiftLen = shiftLen + startHighlight.length() 546 | + endHighlight.length(); 547 | } 548 | 549 | return res; 550 | } 551 | 552 | /** 553 | * Generate java code from javauto code with the help of our template 554 | * 555 | * @param javautoCode 556 | * raw javauto code to be converted 557 | * @param userClassName 558 | * the name of the class/output file 559 | * @return java code as String 560 | */ 561 | private static String generateJavaCode(String javautoCode, 562 | String userClassName) { 563 | /* get a template for our generated code */ 564 | String templateContents = template; 565 | 566 | /* get functions that might need to be implimented */ 567 | ArrayList javautoFunctions = getFunctions(); 568 | 569 | /* define where we're gonna store our final code */ 570 | String generatedCode = ""; 571 | 572 | /* code we generate (supporting functions will be handled later on) */ 573 | String generatedImports = generateImports(); 574 | String generatedVariables = generateVariables(); 575 | 576 | /* define different variables to categorize the user code */ 577 | String userImports = ""; 578 | String userGlobalVariables = ""; 579 | String userCode = ""; 580 | String userFunctions = ""; 581 | 582 | /* handle python file string replacements in user code */ 583 | javautoCode = doPythonStringReplacements(javautoCode); 584 | 585 | /* remove comments from the user code */ 586 | javautoCode = removeComments(javautoCode); 587 | 588 | /* remove whitespace */ 589 | String cleanedCode = ""; 590 | for (String line : javautoCode.split("\n")) { 591 | if (!line.equals("\n")) { 592 | cleanedCode = cleanedCode + line.trim() + "\n"; 593 | } 594 | } 595 | while (cleanedCode.contains("\n\n")) 596 | cleanedCode = cleanedCode.replace("\n\n", "\n"); 597 | javautoCode = cleanedCode; 598 | 599 | /* extract user imports */ 600 | String[] jaCodeLines = javautoCode.split("\n"); 601 | verbose("Getting user imports... ", 0); 602 | printedResults = false; 603 | for (int i = 0; i < jaCodeLines.length; i++) { 604 | if (jaCodeLines[i].trim().startsWith("import ")) { 605 | if (!alreadyImported(jaCodeLines[i].trim(), generatedImports)) { 606 | userImports = userImports + jaCodeLines[i].trim() + "\n"; 607 | verbose(YELLOW 608 | + jaCodeLines[i].trim().substring( 609 | jaCodeLines[i].trim().lastIndexOf(".") + 1, 610 | jaCodeLines[i].trim().lastIndexOf(";")) 611 | + " " + NORMAL, 0); 612 | printedResults = true; 613 | } 614 | jaCodeLines[i] = ""; 615 | } 616 | } 617 | if (!printedResults) 618 | verbose("None", 0); 619 | verbose(""); 620 | 621 | /* rebuild code without imports */ 622 | javautoCode = ""; 623 | for (String line : jaCodeLines) 624 | javautoCode = javautoCode + line + "\n"; 625 | 626 | /* extract user global/class level variables */ 627 | verbose("Getting user global variables... ", 0); 628 | printedResults = false; 629 | jaCodeLines = javautoCode.split("\n"); 630 | for (int i = 0; i < jaCodeLines.length; i++) { 631 | if (jaCodeLines[i].trim().startsWith("global ")) { 632 | boolean empty = false; 633 | if (!jaCodeLines[i].trim().contains("=")) 634 | empty = true; // they're just declaring it, not assigning 635 | // value 636 | String[] declarationParts = jaCodeLines[i].trim().split(" "); 637 | if (declarationParts[2].endsWith(";")) 638 | declarationParts[2] = declarationParts[2].substring(0, 639 | declarationParts[2].length() - 1); 640 | verbose(YELLOW + declarationParts[2] + " " + NORMAL, 0); 641 | printedResults = true; 642 | userGlobalVariables = userGlobalVariables + "public static " 643 | + declarationParts[1] + " " + declarationParts[2] 644 | + ";\n"; 645 | String restOfDeclaration = ""; 646 | for (int j = 2; j < declarationParts.length; j++) 647 | restOfDeclaration = restOfDeclaration + declarationParts[j] 648 | + " "; 649 | jaCodeLines[i] = restOfDeclaration; 650 | if (empty) 651 | jaCodeLines[i] = ""; 652 | } 653 | } 654 | javautoCode = ""; 655 | for (String line : jaCodeLines) 656 | javautoCode = javautoCode + line + "\n"; 657 | if (!printedResults) 658 | verbose("None", 0); 659 | verbose(""); 660 | 661 | /* extract user defined functions from code */ 662 | verbose("Getting user functions... ", 0); 663 | String[] codeParts = splitUserFunctions(javautoCode); 664 | if (!printedResults) 665 | verbose("None", 0); 666 | verbose(""); 667 | userFunctions = codeParts[0]; 668 | userCode = codeParts[1]; 669 | 670 | /* clean up the main user code */ 671 | while (userCode.contains("\n\n")) 672 | userCode = userCode.replace("\n\n", "\n"); 673 | userCode = indent(userCode, 2); 674 | 675 | /* 676 | * insert ~most~ of our generated and user sourced code into the 677 | * template 678 | */ 679 | generatedCode = templateContents; 680 | generatedCode = generatedCode.replace("", "}"); 681 | generatedCode = generatedCode.replace("", userImports); 682 | generatedCode = generatedCode.replace("", 683 | "public class " + userClassName + " {"); 684 | generatedCode = generatedCode.replace("", 685 | indent(userGlobalVariables)); 686 | generatedCode = generatedCode.replace("", 687 | "\tpublic static void main(String[] args) {\n" + userCode 688 | + "\n\t}\n"); 689 | generatedCode = generatedCode.replace("", 690 | indent(userFunctions)); 691 | 692 | /* 693 | * now we generate javauto functions based on what the user has 694 | * implemented until no replacements have been made 695 | */ 696 | int replacements = 1; 697 | ArrayList alreadyGenerated = new ArrayList(); 698 | verbose("Generating functions... ", 0); 699 | printedResults = false; 700 | String noLiteralsCode; 701 | while (replacements != 0) { 702 | replacements = 0; 703 | noLiteralsCode = removeLiterals(generatedCode); 704 | for (String[] javautoFunction : javautoFunctions) { 705 | /* 706 | * if a the function name + ( is present anywhere in our code 707 | * AND we haven't already generated a function for it 708 | */ 709 | if (noLiteralsCode.contains(javautoFunction[0].trim()) 710 | && !alreadyGenerated 711 | .contains(javautoFunction[0].trim())) { 712 | /* add code for that function to the file */ 713 | generatedCode = generatedCode.replace( 714 | "<{_*_generatedFunctions_*_}>", 715 | removeComments(javautoFunction[1]) 716 | + "\n<{_*_generatedFunctions_*_}>"); 717 | verbose(YELLOW + javautoFunction[0] + " " + NORMAL, 0); 718 | printedResults = true; 719 | 720 | /* add function to the list of already generated functions */ 721 | alreadyGenerated.add(javautoFunction[0]); 722 | 723 | /* there's been a replacement => increment the variable */ 724 | replacements++; 725 | 726 | } 727 | } 728 | } 729 | if (!printedResults) 730 | verbose("None", 0); 731 | verbose(""); 732 | 733 | /* 734 | * we've generated all the functions we need => remove the 735 | * tag 736 | */ 737 | generatedCode = generatedCode.replace("<{_*_generatedFunctions_*_}>", 738 | ""); 739 | 740 | /* build a list of class variable declarations and their variable names */ 741 | ArrayList classVariableData = new ArrayList(); 742 | for (String line : generatedVariables.split("\n")) { 743 | String[] parts = line.split("=")[0].split(" "); 744 | String name = parts[parts.length - 1].trim(); 745 | 746 | /* make class variables static */ 747 | String[] lineParts = line.trim().split(" "); 748 | String modifiedLine = lineParts[0] + " static "; 749 | 750 | for (int i = 1; i < lineParts.length; i++) { 751 | modifiedLine = modifiedLine + lineParts[i] + " "; 752 | } 753 | 754 | String[] data = { name, "\t" + modifiedLine.trim() }; 755 | classVariableData.add(data); 756 | } 757 | 758 | /* check if the names are in the code => add the variable if they are */ 759 | String usedVariables = ""; 760 | String skeletonCode = removeLiterals(generatedCode); 761 | verbose("Generating class variables... ", 0); 762 | printedResults = false; 763 | for (String[] declaration : classVariableData) { 764 | if (skeletonCode.contains(declaration[0])) { 765 | usedVariables = usedVariables + declaration[1] + "\n"; 766 | verbose(YELLOW + declaration[0] + " " + NORMAL, 0); 767 | printedResults = true; 768 | } 769 | } 770 | if (!printedResults) 771 | verbose("None", 0); 772 | verbose(""); 773 | 774 | /* add all the variables we determine have been used */ 775 | generatedCode = generatedCode.replace("", 776 | usedVariables); 777 | 778 | /* update the skeletonCode to inclue the generated variables */ 779 | skeletonCode = removeLiterals(generatedCode); 780 | 781 | /* build a list of imported classes */ 782 | ArrayList generatedImportData = new ArrayList(); 783 | for (String line : generatedImports.split("\n")) { 784 | String importedClass = line.substring(line.lastIndexOf(".") + 1, 785 | line.lastIndexOf(";")); 786 | String[] data = { importedClass, line }; 787 | generatedImportData.add(data); 788 | } 789 | 790 | /* check if class names are in code => add the import if they are */ 791 | generatedImports = ""; 792 | verbose("Generating imports... ", 0); 793 | printedResults = false; 794 | for (String[] d : generatedImportData) { 795 | if (skeletonCode.contains(d[0]) || d[0].equals("*")) { 796 | generatedImports = generatedImports + d[1] + "\n"; 797 | verbose(YELLOW + d[0] + " " + NORMAL, 0); 798 | printedResults = true; 799 | } 800 | } 801 | if (!printedResults) 802 | verbose("None", 0); 803 | verbose(""); 804 | 805 | /* parse out user struct declarations */ 806 | verbose("Generating struct objects... ", 0); 807 | printedResults = false; 808 | String structName = ""; 809 | do { 810 | String[] sParts = getStruct(generatedCode); 811 | structName = sParts[1]; 812 | if (!structName.trim().equals("")) { 813 | structFiles.add(new String[] { sParts[1], sParts[2] }); 814 | verbose(YELLOW + structName + " " + NORMAL, 0); 815 | printedResults = true; 816 | generatedCode = sParts[0]; 817 | } 818 | } while (!structName.trim().equals("")); 819 | if (!printedResults) 820 | verbose("None", 0); 821 | verbose(""); 822 | 823 | /* check if class names are in structs => add the import if they are */ 824 | for (String[] d : generatedImportData) { 825 | for (int j = 0; j < structFiles.size(); j++) { 826 | String[] structFile = structFiles.get(j); 827 | if (structFile[1].contains(d[0]) || d[0].equals("*")) { 828 | structFile[1] = d[1] + "\n" + structFile[1]; 829 | structFiles.set(j, structFile); 830 | } 831 | } 832 | } 833 | 834 | /* add all the imports we determine have been used */ 835 | generatedCode = generatedCode.replace("", 836 | generatedImports); 837 | 838 | /* get rid of all empty lines */ 839 | String[] generatedCodeLines = generatedCode.split("\n"); 840 | generatedCode = ""; 841 | for (int i = 0; i < generatedCodeLines.length; i++) { 842 | if (!generatedCodeLines[i].trim().equals("")) 843 | generatedCode = generatedCode + generatedCodeLines[i] + "\n"; 844 | } 845 | 846 | return generatedCode; 847 | } 848 | 849 | /** 850 | * Searches user code for a struct, pieces it together, and returns the 851 | * struct code and the new user code. 852 | * 853 | * @param code 854 | * the user code 855 | * @return String array index 0: new user code index 1: the struct name 856 | * index 2: the struct code 857 | */ 858 | private static String[] getStruct(String code) { 859 | /* split the user code into lines and characters for parsing */ 860 | String[] codeLines = code.split("\n"); 861 | char[] codeChars = code.toCharArray(); 862 | 863 | /* get the indexes of string/character literals and comments */ 864 | ArrayList> ignores = getIgnoreIndexes(code); 865 | ArrayList allIgnores = new ArrayList(); 866 | allIgnores.addAll(ignores.get(0)); 867 | allIgnores.addAll(ignores.get(1)); 868 | 869 | /* look for a struct declaration */ 870 | int startIndex = 0; 871 | for (int i = 0; i < codeLines.length; i++) { 872 | /* if a line starts with struct it's a struct declaration */ 873 | if (removeComments(codeLines[i]).trim().startsWith("struct ")) { 874 | /* 875 | * increment the start index until we're at the beginning of the 876 | * declaration 877 | */ 878 | while (inIgnoredText(startIndex, allIgnores) 879 | || codeChars[startIndex] != 's') 880 | startIndex++; 881 | 882 | /* find the index of the last bracket in the struct */ 883 | int endIndex = startIndex; 884 | String insideElements = ""; 885 | while (endIndex < codeChars.length) { 886 | if (codeChars[endIndex] == '{' 887 | && !inIgnoredText(endIndex, allIgnores)) { 888 | break; 889 | } 890 | endIndex++; 891 | } 892 | endIndex++; 893 | while (endIndex < codeChars.length) { 894 | if (codeChars[endIndex] == '}' 895 | && !inIgnoredText(endIndex, allIgnores)) { 896 | break; 897 | } 898 | insideElements = insideElements 899 | + String.valueOf(codeChars[endIndex]); 900 | endIndex++; 901 | } 902 | endIndex++; 903 | 904 | /* get the user code without the struct object */ 905 | String newCode = code.substring(0, startIndex) 906 | + code.substring(endIndex, codeChars.length); 907 | 908 | /* get the name of the struct object to create */ 909 | String structName = removeComments( 910 | code.substring(startIndex, endIndex)).split(" ")[1] 911 | .trim(); 912 | 913 | /* get each individual variable within the struct */ 914 | String[] insideElementsLines = insideElements.split("\n"); 915 | for (int j = 0; j < insideElementsLines.length; j++) { 916 | insideElementsLines[j] = removeComments( 917 | insideElementsLines[j]).trim(); 918 | } 919 | insideElements = ""; 920 | for (String s : insideElementsLines) 921 | insideElements = insideElements + s; 922 | String[] elements = insideElements.split(";"); 923 | for (int j = 0; j < elements.length; j++) 924 | elements[j] = "public " + elements[j].trim() + ";"; 925 | 926 | /* construct java code from these elements */ 927 | String elementCode = ""; 928 | for (String e : elements) 929 | elementCode = elementCode + "\t" + e + "\n"; 930 | elementCode = elementCode 931 | .substring(0, elementCode.length() - 1); 932 | 933 | /* construct code for the whole struct */ 934 | String structCode = "public class " + structName + " {\n" 935 | + elementCode + "\n}"; 936 | 937 | /* return our results */ 938 | return new String[] { newCode, structName, structCode }; 939 | } 940 | startIndex = startIndex + codeLines[i].length() + 1; // +1 for the 941 | // \n char 942 | } 943 | /* if we don't find anything */ 944 | return new String[] { code, "", "" }; 945 | } 946 | 947 | /** 948 | * Get the end index of a function 949 | * 950 | * @param userCode 951 | * the text from which to extract the function 952 | * @param lowerBound 953 | * the start index of the function 954 | * @return the end index of the function 955 | */ 956 | private static int getFunctionUpperBound(String userCode, int lowerBound) { 957 | /* get the code as a char array */ 958 | char[] codeChars = userCode.toCharArray(); 959 | 960 | /* get the indexes of string/character literals and comments */ 961 | ArrayList> ignores = getIgnoreIndexes(userCode); 962 | ArrayList allIgnores = new ArrayList(); 963 | allIgnores.addAll(ignores.get(0)); 964 | allIgnores.addAll(ignores.get(1)); 965 | 966 | int startIndex = lowerBound; 967 | 968 | /* find the index of the first bracket in the func */ 969 | int endIndex = startIndex; 970 | while (endIndex < codeChars.length) { 971 | if (codeChars[endIndex] == '{' 972 | && !inIgnoredText(endIndex, allIgnores)) { 973 | break; 974 | } 975 | endIndex++; 976 | } 977 | endIndex++; 978 | 979 | /* find the value of the last bracket in the func */ 980 | int open = 1; 981 | int close = 0; 982 | while (open > close) { 983 | if (codeChars[endIndex] == '}' 984 | && !inIgnoredText(endIndex, allIgnores)) { 985 | close++; 986 | } else if (codeChars[endIndex] == '{' 987 | && !inIgnoredText(endIndex, allIgnores)) { 988 | open++; 989 | } 990 | endIndex++; 991 | } 992 | return endIndex; 993 | } 994 | 995 | /** 996 | * Split user code into an array; one indice will contain user functions and 997 | * the other will contain all other user code. 998 | * 999 | * @param userCode 1000 | * @return String[] { userFunctions, userCode } 1001 | */ 1002 | private static String[] splitUserFunctions(String userCode) { 1003 | /* two variables to hold the two parts of the code */ 1004 | String userFunctions = ""; 1005 | String userNormalCode = ""; 1006 | 1007 | /* keep track of the character index we're at */ 1008 | int charIndex = 0; 1009 | 1010 | /* create a list to store function start & end indexes */ 1011 | ArrayList functionIndexes = new ArrayList(); 1012 | 1013 | /* iterate by lines looking for functions */ 1014 | for (String line : userCode.split("\n")) { 1015 | /* check for function declaration */ 1016 | if (line.trim().startsWith("func ")) { 1017 | int[] bounds = { charIndex, 1018 | getFunctionUpperBound(userCode, charIndex) }; 1019 | functionIndexes.add(bounds); 1020 | } 1021 | 1022 | /* advance the character index (+1 for the \n char) */ 1023 | charIndex = charIndex + line.length() + 1; 1024 | } 1025 | 1026 | /* split the original string into parts based on the function bounds */ 1027 | int nonFunctionIndex = 0; 1028 | for (int[] bounds : functionIndexes) { 1029 | /* 1030 | * append what is outside the function bounds to the userNormalCode 1031 | * variable 1032 | */ 1033 | userNormalCode = userNormalCode 1034 | + userCode.substring(nonFunctionIndex, bounds[0]) + "\n"; 1035 | 1036 | /* 1037 | * get the current user function & change its first line for java 1038 | * func decalration 1039 | */ 1040 | String[] functionLines = userCode.substring(bounds[0], bounds[1]) 1041 | .split("\n"); 1042 | functionLines[0] = functionLines[0].trim(); 1043 | 1044 | /* remove the first five letters; the "func " & add in public */ 1045 | functionLines[0] = "public static " + functionLines[0].substring(5); 1046 | 1047 | /* get the function name for verbose output */ 1048 | String[] fparts = functionLines[0].split(" "); 1049 | String restoff = ""; 1050 | for (int i = 3; i < fparts.length; i++) 1051 | restoff = restoff + fparts[i] + " "; 1052 | verbose(YELLOW + restoff.substring(0, restoff.indexOf("(")) + " " 1053 | + NORMAL, 0); 1054 | printedResults = true; 1055 | 1056 | /* add each of the elements in the array together into a function */ 1057 | String function = ""; 1058 | for (int i = 0; i < functionLines.length; i++) { 1059 | if (i != 0 && i < functionLines.length - 1) 1060 | function = function + "\t" + functionLines[i] + "\n"; 1061 | else 1062 | function = function + functionLines[i] + "\n"; 1063 | 1064 | } 1065 | 1066 | /* 1067 | * append what is inside the function bounds to the userFunctions 1068 | * variable 1069 | */ 1070 | userFunctions = userFunctions + function + "\n\n"; 1071 | 1072 | /* 1073 | * advance the lower bound of the "non function" code to the upper 1074 | * bound of the function code 1075 | */ 1076 | nonFunctionIndex = bounds[1]; 1077 | } 1078 | 1079 | /* add any remaining code to the user "non-function" code */ 1080 | userNormalCode = userNormalCode 1081 | + userCode.substring(nonFunctionIndex, userCode.length()); 1082 | 1083 | /* return the two parts */ 1084 | String[] r = { userFunctions, userNormalCode }; 1085 | return r; 1086 | } 1087 | 1088 | /** 1089 | * Search the javautoFile for imports and add them all to the generated 1090 | * imports 1091 | * 1092 | * @return imports that have been generated 1093 | */ 1094 | private static String generateImports() { 1095 | /* get raw file contents of the file containing our imports */ 1096 | String[] importContents = resourceRead(javautoFile).split("\n"); 1097 | 1098 | /* variable to store our generated imports */ 1099 | String imports = ""; 1100 | 1101 | /* add each line that starts with "import " to our imports variable */ 1102 | for (String importLine : importContents) { 1103 | if (importLine.startsWith("import ")) 1104 | imports = imports + importLine + "\n"; 1105 | } 1106 | 1107 | /* return our imports */ 1108 | return imports; 1109 | } 1110 | 1111 | /** 1112 | * Search the javautoFile for all class variables and return them 1113 | * 1114 | * @return class variables that have been generated 1115 | */ 1116 | private static String generateVariables() { 1117 | /* get raw file contents of the file containing our variables */ 1118 | String[] variablesContents = resourceRead(javautoFile).split("\n"); 1119 | 1120 | /* variable to store our generated class vars */ 1121 | String classVars = ""; 1122 | 1123 | /* add each line that has a class varaible to our classVars */ 1124 | for (String line : variablesContents) { 1125 | if ((line.trim().startsWith("public ") || line.trim().startsWith( 1126 | "private ")) 1127 | && line.trim().endsWith(";")) 1128 | classVars = classVars + line + "\n"; 1129 | } 1130 | 1131 | /* return our class vars */ 1132 | return classVars; 1133 | } 1134 | 1135 | /** 1136 | * Gets a list of functions and their source code from the javautoFile 1137 | * 1138 | * @return ArrayList with each element containing {function name, 1139 | * function code} 1140 | */ 1141 | private static ArrayList getFunctions() { 1142 | /* define the list where we'll store all the data */ 1143 | ArrayList functionDataList = new ArrayList(); 1144 | 1145 | /* get raw file contents of the file containing our functions */ 1146 | String functionContents = resourceRead(javautoFile); 1147 | 1148 | /* split into lines for evaluation */ 1149 | String[] functionContentsLines = functionContents.split("\n"); 1150 | 1151 | /* check each line and extract function names */ 1152 | for (String line : functionContentsLines) { 1153 | /* 1154 | * if the line is like "public *{" or "private *{" but isn't like 1155 | * "public class" 1156 | */ 1157 | if ((line.trim().startsWith("public ") || line.trim().startsWith( 1158 | "private ")) 1159 | && (line.trim().endsWith("{")) 1160 | && (!line.trim().startsWith("public class"))) { 1161 | /* 1162 | * if it meets the above criteria it's a function & we add it to 1163 | * the list 1164 | */ 1165 | 1166 | /* get function name & code */ 1167 | String functionName = line.trim().split(" ")[2].split("[(]")[0]; 1168 | String functionCode = getFunctionCode(line, functionContents); 1169 | 1170 | /* 1171 | * modify the function code so that the declaration becomes 1172 | * static 1173 | */ 1174 | String[] lines = functionCode.split("\n"); 1175 | lines[0] = lines[0].trim(); 1176 | if (lines[0].startsWith("private ")) { 1177 | lines[0] = "\tprivate static " + lines[0].substring(8); 1178 | } else if (lines[0].startsWith("public ")) { 1179 | lines[0] = "\tpublic static " + lines[0].substring(7); 1180 | } 1181 | functionCode = ""; 1182 | for (String l : lines) 1183 | functionCode = functionCode + l + "\n"; 1184 | 1185 | /* 1186 | * add it to the list unless it's the "run" function used in a 1187 | * thread 1188 | */ 1189 | if (!functionName.toLowerCase().equals("run")) { 1190 | String[] function = { functionName.trim(), functionCode }; 1191 | functionDataList.add(function); 1192 | } 1193 | } 1194 | } 1195 | 1196 | /* return our list without duplicates */ 1197 | return combineFunctionDuplicates(functionDataList); 1198 | } 1199 | 1200 | /** 1201 | * Take an array list with each item having a format {function name, 1202 | * function code} and combine duplicate function names into one entry that 1203 | * still has the source code of each so an array list containing two 1204 | * elements like this: {doSomething, code1}, {doSomething, code2} would 1205 | * become {doSomething, code1\n\ncode2} combineFunctionDuplicates() is 1206 | * necessary because some of our functions are defined multiple times to 1207 | * allow for different parameters and this allows us to add all iterations 1208 | * of a function at once. 1209 | * 1210 | * @param functionListWithDuplicates 1211 | * the list to run through 1212 | * @return a version of the list without duplicates but with all the code 1213 | */ 1214 | private static ArrayList combineFunctionDuplicates( 1215 | ArrayList functionListWithDuplicates) { 1216 | /* define our final list that wont have duplicates */ 1217 | ArrayList functionListNoDuplicates = new ArrayList(); 1218 | 1219 | /* list to keep track of function names that have already been combined */ 1220 | ArrayList alreadyCombined = new ArrayList(); 1221 | 1222 | for (String[] f : functionListWithDuplicates) { 1223 | /* the name of the function is stored in the first indice */ 1224 | String functionName = f[0]; 1225 | 1226 | /* if we haven't already combined the function */ 1227 | if (!alreadyCombined.contains(functionName)) { 1228 | /* the combined code of all functions of the same name */ 1229 | String combinedCode = ""; 1230 | 1231 | /* check every item in the list */ 1232 | for (String[] function : functionListWithDuplicates) { 1233 | /* if the names match add the code in */ 1234 | if (functionName.equals(function[0])) { 1235 | combinedCode = combinedCode + function[1] + "\n\n"; 1236 | } 1237 | } 1238 | 1239 | /* add the function to the list */ 1240 | String[] combinedFunction = { functionName, combinedCode }; 1241 | functionListNoDuplicates.add(combinedFunction); 1242 | 1243 | /* mark the name as covered */ 1244 | alreadyCombined.add(functionName); 1245 | } 1246 | } 1247 | 1248 | /* return our final results */ 1249 | return functionListNoDuplicates; 1250 | } 1251 | 1252 | /** 1253 | * Get the code for a single function from a java file of functions based 1254 | * off its signature 1255 | * 1256 | * @param signature 1257 | * All or part of the function signature, eg. 1258 | * "public void function(int i)" If there are two declarations 1259 | * with the same name and you only provide 1260 | * "public void functionName" it will return the first one. To 1261 | * get a specific one include the full signature like 1262 | * "public void functionName(int i, int j)" 1263 | * @param fullFunctionsText 1264 | * The contents of a java file that contains the function we're 1265 | * trying to extract 1266 | * @return Full text of the single function we're trying to find 1267 | */ 1268 | private static String getFunctionCode(String signature, String wholeFile) { 1269 | /* find the index of the function */ 1270 | int funcIndex = wholeFile.indexOf(signature); 1271 | 1272 | /* trim the file so that it starts at this index */ 1273 | wholeFile = wholeFile.substring(funcIndex); 1274 | 1275 | /* file as string -> file as char array */ 1276 | char[] wholeFileChars = wholeFile.toCharArray(); 1277 | 1278 | /* variables to hold position and brace counts */ 1279 | int index = 0; 1280 | int openBrace = 0; 1281 | int closeBrace = 0; 1282 | 1283 | /* find the opening bracket of function */ 1284 | while (openBrace == 0) { 1285 | 1286 | /* if we find the brace we're done */ 1287 | if (wholeFileChars[index] == '{') { 1288 | openBrace++; 1289 | index++; 1290 | } 1291 | 1292 | /* check for different kinds of comments */ 1293 | else if (wholeFileChars[index] == '/') { 1294 | index++; 1295 | 1296 | /* if it's // comment until end of line */ 1297 | if (wholeFileChars[index] == '/') { 1298 | while (wholeFileChars[index] != '\n') { 1299 | index++; 1300 | } 1301 | index++; 1302 | } 1303 | 1304 | /* if it's a /* comment until * / */ 1305 | else if (wholeFileChars[index] == '*') { 1306 | index++; 1307 | boolean done = false; 1308 | while (done == false) { 1309 | if (wholeFileChars[index] == '*') { 1310 | index++; 1311 | if (wholeFileChars[index] == '/') { 1312 | index++; 1313 | done = true; 1314 | } 1315 | } else { 1316 | index++; 1317 | } 1318 | } 1319 | } 1320 | } 1321 | 1322 | /* if it's some other character just keep going */ 1323 | else { 1324 | index++; 1325 | } 1326 | } 1327 | 1328 | while (openBrace > closeBrace) { 1329 | /* if we find a brace then increment */ 1330 | if (wholeFileChars[index] == '{') { 1331 | openBrace++; 1332 | index++; 1333 | } else if (wholeFileChars[index] == '}') { 1334 | closeBrace++; 1335 | index++; 1336 | } 1337 | 1338 | /* check for string literals */ 1339 | else if (wholeFileChars[index] == '"') { 1340 | index++; 1341 | while (wholeFileChars[index] != '"') { 1342 | if (wholeFileChars[index] == '\\') { 1343 | index++; 1344 | } 1345 | index++; 1346 | } 1347 | index++; 1348 | } 1349 | 1350 | /* check for character literals */ 1351 | else if (wholeFileChars[index] == '\'') { 1352 | index++; 1353 | while (wholeFileChars[index] != '\'') { 1354 | if (wholeFileChars[index] == '\\') { 1355 | index++; 1356 | } 1357 | index++; 1358 | } 1359 | index++; 1360 | } 1361 | 1362 | /* check for different kinds of comments */ 1363 | else if (wholeFileChars[index] == '/') { 1364 | index++; 1365 | 1366 | /* if it's // comment until end of line */ 1367 | if (wholeFileChars[index] == '/') { 1368 | while (wholeFileChars[index] != '\n') { 1369 | index++; 1370 | } 1371 | index++; 1372 | } 1373 | 1374 | /* if it's a /* comment until * / */ 1375 | else if (wholeFileChars[index] == '*') { 1376 | index++; 1377 | boolean done = false; 1378 | while (done == false) { 1379 | if (wholeFileChars[index] == '*') { 1380 | index++; 1381 | if (wholeFileChars[index] == '/') { 1382 | index++; 1383 | done = true; 1384 | } 1385 | } else { 1386 | index++; 1387 | } 1388 | } 1389 | } 1390 | } 1391 | 1392 | /* if it's some other character just keep going */ 1393 | else { 1394 | index++; 1395 | } 1396 | 1397 | } 1398 | 1399 | return wholeFile.substring(0, index + 1); 1400 | } 1401 | 1402 | /** 1403 | * Handle all python like string replacements ("%s" % something) within a 1404 | * string. 1405 | * 1406 | * @param data 1407 | * Data within which replacements happen. 1408 | * @return Data with all replacements done. 1409 | */ 1410 | private static String doPythonStringReplacements(String data) { 1411 | /* 1412 | * As long as some are being replaced keep replacing them. We have to do 1413 | * this one at a time because as soon as one part is changed the indexes 1414 | * to ignore (string literals and comments) change so we have to rebuild 1415 | * everything 1416 | */ 1417 | String replaced = "some"; 1418 | while (replaced.equals("some")) { 1419 | String[] returned = doPythonStringReplacement(data); 1420 | replaced = returned[1]; 1421 | data = returned[0]; 1422 | } 1423 | return data; 1424 | } 1425 | 1426 | /** 1427 | * Handle a _single_ python style string replacement within a string. For 1428 | * instance, the following string: System.out.println("Time: \t%s" % 1429 | * (time)); Would become: 1430 | * System.out.println("Time: \t%s".replaceFirst("%s",time)); 1431 | * 1432 | * @param data 1433 | * the string to search through and perform a replacement in. 1434 | * @return a string array, the first index being the modified string data, 1435 | * the second index being either "some" or "none", depending on if a 1436 | * replacement was made or if no replacement was made. 1437 | */ 1438 | private static String[] doPythonStringReplacement(String data) { 1439 | /* build a regex for the data */ 1440 | String regexp = "(\".+\")(\\s*%\\s*(\\())"; 1441 | Pattern pattern = Pattern.compile(regexp); 1442 | Matcher matcher = pattern.matcher(data); 1443 | 1444 | /* build ignore lists for the data */ 1445 | ArrayList> ignores = getIgnoreIndexes(data); 1446 | ArrayList commentIgnores = ignores.get(0); 1447 | ArrayList literalIgnores = ignores.get(1); 1448 | 1449 | /* use these indexes to populate a list of general ignore indexes */ 1450 | ArrayList allIgnores = new ArrayList(); 1451 | for (Integer[] j : commentIgnores) 1452 | allIgnores.add(j); 1453 | for (Integer[] j : literalIgnores) 1454 | allIgnores.add(j); 1455 | 1456 | while (matcher.find()) { 1457 | /* use the regex search to get all the relevant indexes */ 1458 | int matchedStartIndex = matcher.start(); 1459 | int literalEndIndex = matchedStartIndex + matcher.group(1).length(); 1460 | int elementsStartIndex = matcher.end() - matcher.group(3).length(); 1461 | 1462 | /* 1463 | * this is the index of the % character -- it's the "check index" 1464 | * because we can check whether it's inside a comment/string to see 1465 | * if we should actually do the modification. 1466 | */ 1467 | int checkIndex = matcher.end() - matcher.group(2).length(); 1468 | 1469 | /* only proceed if the checkIndex isn't inside our ignore list */ 1470 | if (!inIgnoredText(checkIndex, allIgnores)) { 1471 | /* 1472 | * find the upper bound of the elements we're adding into the 1473 | * string 1474 | */ 1475 | int elementsEndIndex = findEndParen(elementsStartIndex, data, 1476 | allIgnores); 1477 | 1478 | /* get the elements that need to be subbed in */ 1479 | ArrayList elements = getElements(elementsStartIndex, 1480 | elementsEndIndex, data, allIgnores); 1481 | 1482 | /* build the .replaceFirst() line */ 1483 | String rCode = ""; 1484 | for (String e : elements) { 1485 | rCode = rCode + ".replaceFirst(\"%s\"," + e + ")"; 1486 | } 1487 | 1488 | /* build the whole literal */ 1489 | String modString = data.substring(matchedStartIndex, 1490 | literalEndIndex) + rCode; 1491 | 1492 | /* build a new string with the replacement */ 1493 | String fixed = data.substring(0, matchedStartIndex) + modString 1494 | + data.substring(elementsEndIndex); 1495 | 1496 | return new String[] { fixed, "some" }; 1497 | } 1498 | } 1499 | 1500 | /* if we get to this point no replacements have been made */ 1501 | return new String[] { data, "none" }; 1502 | } 1503 | 1504 | /** 1505 | * Get each element inside of a tuple like structure. So for a given line of 1506 | * code: String intro = "My name is %s %s %s" % ("John", 1507 | * getMiddleName("John"), getLastName("John")); The tuple-like structure 1508 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The element list 1509 | * would look like ["\"John\"", "getMiddleName(\"John\")", 1510 | * "getLastName(\"John\")"] 1511 | * 1512 | * @param startElement 1513 | * the index of the opening ( of the tuple-like structure 1514 | * @param endElements 1515 | * the index of the closing ) of the tuple-like structure 1516 | * @param context 1517 | * the greater string in which it resides 1518 | * @param indexesToIgnore 1519 | * a list of index bounds we want to ignore, eg comments or 1520 | * string literals. Each element should have the format 1521 | * [startOfIgnore, endOfIgnore] 1522 | * @return a list of individual elements 1523 | */ 1524 | private static ArrayList getElements(int startElement, 1525 | int endElement, String context, ArrayList indexesToIgnore) { 1526 | /* get the comma indexes */ 1527 | ArrayList splitIndexes = getElementCommas(startElement, 1528 | endElement, context, indexesToIgnore); 1529 | 1530 | /* add the beginning and end of the structure to the slip indexes */ 1531 | splitIndexes.add(0, startElement); 1532 | splitIndexes.add(endElement - 1); 1533 | 1534 | /* list to hold the elements we parse */ 1535 | ArrayList elements = new ArrayList(); 1536 | 1537 | if (splitIndexes.size() > 0) { 1538 | for (int i = 1; i < splitIndexes.size(); i++) { 1539 | elements.add(context.substring(splitIndexes.get(i - 1) + 1, 1540 | splitIndexes.get(i)).trim()); 1541 | } 1542 | } 1543 | 1544 | return elements; 1545 | } 1546 | 1547 | /** 1548 | * Very specific use. Gets the "real" commas inside of a tuple-like 1549 | * structure. This shows which indexes it would return for an example: 1550 | * ("parameter1", someFunction("foo", getData("foo", "bar")), "parameter3") 1551 | * ^ ^ 1552 | * 1553 | * @param startElement 1554 | * the index of the beginning of the tuple like element 1555 | * @param endElement 1556 | * the index of the end of the tuple like element 1557 | * @param context 1558 | * the String within which this "tuple" is contained 1559 | * @param indexesToIgnore 1560 | * a list of index bounds we want to ignore, eg comments or 1561 | * string literals. Each element should have the format 1562 | * [startOfIgnore, endOfIgnore] 1563 | * @return a List of indexes where "true" commas are present 1564 | */ 1565 | private static ArrayList getElementCommas(int startElement, 1566 | int endElement, String context, ArrayList indexesToIgnore) { 1567 | /* to store our final values */ 1568 | ArrayList realCommas = new ArrayList(); 1569 | 1570 | char[] contextChars = context.toCharArray(); 1571 | 1572 | int index = startElement + 1; // the plus one is to skip the initial ( 1573 | 1574 | /* search through every character in the string */ 1575 | while (index < endElement) { 1576 | /* 1577 | * if it's a comma and it's not inside our comments/literals add it 1578 | * to the list 1579 | */ 1580 | if (contextChars[index] == ',' 1581 | && !inIgnoredText(index, indexesToIgnore)) { 1582 | realCommas.add(index); 1583 | index++; 1584 | } 1585 | /* 1586 | * if it's an open paren but it isn't inside a comment/literal skip 1587 | * to the end paren 1588 | */ 1589 | else if (contextChars[index] == '(' 1590 | && !inIgnoredText(index, indexesToIgnore)) { 1591 | index = findEndParen(index, context, indexesToIgnore); 1592 | } 1593 | /* otherwise it's just a normal character so skip to the next one */ 1594 | else { 1595 | index++; 1596 | } 1597 | } 1598 | 1599 | /* now that we're all the way through return our list */ 1600 | return realCommas; 1601 | } 1602 | 1603 | /** 1604 | * Given the index of a '(', find the corresponding ')'. 1605 | * 1606 | * @param startParen 1607 | * the index of the '('. 1608 | * @param context 1609 | * the string within which the parens are located. 1610 | * @param indexesToIgnore 1611 | * A list of Integers like [start, end] that specify indexes that 1612 | * should be ignored, this list usually contains the start and 1613 | * end bounds of each comment and string literal in the context. 1614 | * @return the index of the closing paren 1615 | */ 1616 | private static int findEndParen(int startParen, String context, 1617 | ArrayList indexesToIgnore) { 1618 | char[] contextChars = context.toCharArray(); 1619 | int index = startParen + 1; 1620 | int open = 1; 1621 | int close = 0; 1622 | while (open > close) { 1623 | /* 1624 | * if the current character is a ( and it's not inside a comment or 1625 | * literal 1626 | */ 1627 | if (contextChars[index] == '(' 1628 | && !inIgnoredText(index, indexesToIgnore)) { 1629 | open++; 1630 | } 1631 | /* 1632 | * if the current character is a ) and it's not inside a comment or 1633 | * literal 1634 | */ 1635 | else if (contextChars[index] == ')' 1636 | && !inIgnoredText(index, indexesToIgnore)) { 1637 | close++; 1638 | } 1639 | /* on to the next one */ 1640 | index++; 1641 | } 1642 | return index; 1643 | } 1644 | 1645 | /** 1646 | * Determines if a character is inside any of the bounds of a list of blocks 1647 | * of text to ignore. 1648 | * 1649 | * @param charIndex 1650 | * the index of the character whose position is being checked 1651 | * @param ignoredIndex 1652 | * a list of items like [int startIgnoreIndex, int 1653 | * endIgnoreIndex] that specifies which indexes are supposed to 1654 | * be ignored 1655 | * @return returns true if the character index is within any of the ignore 1656 | * bounds, otherwise returns false. 1657 | */ 1658 | private static boolean inIgnoredText(int charIndex, 1659 | ArrayList ignoredIndexes) { 1660 | /* check each set of bounds to see if they hold our charIndex */ 1661 | for (Integer[] i : ignoredIndexes) { 1662 | if (charIndex >= i[0] && charIndex <= i[1]) 1663 | return true; 1664 | } 1665 | 1666 | /* if we got to here we haven't found it inside any of the bounds */ 1667 | return false; 1668 | } 1669 | 1670 | /** 1671 | * Build a list of character indexes that should be ignored during 1672 | * processing. Characters to be ignored are those inside of comments, string 1673 | * literals, and character literals. This function returns the bounds of 1674 | * indexes of characters and literals in two separate lists. 1675 | * 1676 | * @param code 1677 | * the string to generate this list of bounds for 1678 | * @return returns two ArrayList objects, wrapped inside of one 1679 | * ArrayList, with the format [comment indexes, literal indexes]. 1680 | * Then each of those elements is a list with the format [start 1681 | * ignore index, end ignore index]. 1682 | */ 1683 | private static ArrayList> getIgnoreIndexes(String code) { 1684 | /* Lists to hold bounds for both comments and literals */ 1685 | ArrayList commentIndexes = new ArrayList(); 1686 | ArrayList literalIndexes = new ArrayList(); 1687 | 1688 | /* 1689 | * List to hold our other two lists, so that the user can separate them 1690 | * at will 1691 | */ 1692 | ArrayList> finalValues = new ArrayList>(); 1693 | 1694 | /* 1695 | * iterate through character by character looking for comments and 1696 | * literals 1697 | */ 1698 | char[] codeChars = code.toCharArray(); 1699 | int index = 0; 1700 | while (index < codeChars.length) { 1701 | if (codeChars[index] == '/') { 1702 | Integer startIndex = -1; 1703 | Integer endIndex = -1; 1704 | 1705 | index++; 1706 | 1707 | if (codeChars[index] == '/') { 1708 | startIndex = index - 1; 1709 | index++; 1710 | while (codeChars[index] != '\n') { 1711 | index++; 1712 | if (index == codeChars.length) { 1713 | index--; 1714 | break; 1715 | } 1716 | } 1717 | endIndex = index; 1718 | index++; 1719 | } else if (codeChars[index] == '*') { 1720 | startIndex = index - 1; 1721 | index++; 1722 | boolean done = false; 1723 | while (!done) { 1724 | if (codeChars[index] == '*') { 1725 | index++; 1726 | if (codeChars[index] == '/') { 1727 | done = true; 1728 | endIndex = index; 1729 | } 1730 | } 1731 | index++; 1732 | } 1733 | } 1734 | 1735 | /* if we found stuff add to array */ 1736 | if (startIndex != -1) 1737 | commentIndexes.add(new Integer[] { startIndex, endIndex }); 1738 | } else if (codeChars[index] == '"') { 1739 | Integer startIndex = index; 1740 | Integer endIndex = -1; 1741 | index++; 1742 | 1743 | while (codeChars[index] != '"') { 1744 | if (codeChars[index] == '\\') { 1745 | index++; 1746 | } 1747 | index++; 1748 | } 1749 | endIndex = index; 1750 | index++; 1751 | 1752 | /* add to array */ 1753 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 1754 | } else if (codeChars[index] == '\'') { 1755 | Integer startIndex = index; 1756 | Integer endIndex = -1; 1757 | index++; 1758 | 1759 | while (codeChars[index] != '\'') { 1760 | if (codeChars[index] == '\\') { 1761 | index++; 1762 | } 1763 | index++; 1764 | } 1765 | endIndex = index; 1766 | index++; 1767 | 1768 | /* add to array */ 1769 | literalIndexes.add(new Integer[] { startIndex, endIndex }); 1770 | } else { 1771 | index++; 1772 | } 1773 | } 1774 | 1775 | /* put our two lists inside of a third list */ 1776 | finalValues.add(commentIndexes); 1777 | finalValues.add(literalIndexes); 1778 | 1779 | /* return our final list */ 1780 | return finalValues; 1781 | } 1782 | 1783 | /** 1784 | * Removes all comments from a String and return the stripped String 1785 | * "Th/*comment*\/is line //other stuff" becomes "This line" Necessary so 1786 | * that line by line searching for beginning/ending with things can be 1787 | * accurate 1788 | * 1789 | * @param commented 1790 | * The String to remove comments from 1791 | * @return String stripped of comments 1792 | */ 1793 | private static String removeComments(String commented) { 1794 | /* string -> char array, so we can analyze one char at a time */ 1795 | char[] commentedChars = commented.toCharArray(); 1796 | 1797 | /* variable to hold our position */ 1798 | int index = 0; 1799 | 1800 | /* variable to hold our final String */ 1801 | String noComments = ""; 1802 | 1803 | /* go through each character */ 1804 | while (index < commentedChars.length) { 1805 | /* check for a string literal */ 1806 | if (commentedChars[index] == '"') { 1807 | /* 1808 | * we don't want to remove something that looks like a comment 1809 | * if it's in here 1810 | */ 1811 | noComments = noComments + String.valueOf(commentedChars[index]); 1812 | index++; 1813 | while (commentedChars[index] != '"') { 1814 | noComments = noComments 1815 | + String.valueOf(commentedChars[index]); 1816 | if (commentedChars[index] == '\\') { 1817 | index++; 1818 | noComments = noComments 1819 | + String.valueOf(commentedChars[index]); 1820 | } 1821 | index++; 1822 | } 1823 | noComments = noComments + String.valueOf(commentedChars[index]); 1824 | index++; 1825 | } 1826 | 1827 | /* check for character literals */ 1828 | else if (commentedChars[index] == '\'') { 1829 | noComments = noComments + String.valueOf(commentedChars[index]); 1830 | index++; 1831 | while (commentedChars[index] != '\'') { 1832 | noComments = noComments 1833 | + String.valueOf(commentedChars[index]); 1834 | if (commentedChars[index] == '\\') { 1835 | index++; 1836 | noComments = noComments 1837 | + String.valueOf(commentedChars[index]); 1838 | } 1839 | index++; 1840 | } 1841 | noComments = noComments + String.valueOf(commentedChars[index]); 1842 | index++; 1843 | } 1844 | 1845 | /* check for the start of a comment */ 1846 | else if (commentedChars[index] == '/') { 1847 | index++; 1848 | 1849 | /* if it's this // kind of comment */ 1850 | if (commentedChars[index] == '/') { 1851 | index++; 1852 | while (commentedChars[index] != '\n') { 1853 | index++; 1854 | if (index >= commentedChars.length) { 1855 | return noComments; 1856 | } 1857 | } 1858 | noComments = noComments + "\n"; 1859 | index++; 1860 | } 1861 | /* if it's this /* kind of comment */ 1862 | else if (commentedChars[index] == '*') { 1863 | index++; 1864 | boolean done = false; 1865 | while (done == false) { 1866 | /* maybe it's finishing... */ 1867 | if (commentedChars[index] == '*') { 1868 | index++; 1869 | if (commentedChars[index] == '/') { 1870 | done = true; 1871 | } 1872 | index++; 1873 | } else { 1874 | index++; 1875 | } 1876 | 1877 | } 1878 | } 1879 | /* if it's not even a comment */ 1880 | else { 1881 | noComments = noComments + "/"; 1882 | } 1883 | } 1884 | 1885 | /* if there's no doubt just add it on */ 1886 | else { 1887 | noComments = noComments + String.valueOf(commentedChars[index]); 1888 | index++; 1889 | } 1890 | } 1891 | return noComments; 1892 | } 1893 | 1894 | /** 1895 | * Removes all String/char literals from a String and return the stripped 1896 | * String "System.out.println("\"Hello,\" he said." + 1897 | * String.valueOf('\n'));" becomes "System.out.println( + 1898 | * String.valueOf());" Doesn't remove literals from comments, so 1899 | * "// Method "removeLiterals" removes literals" would be untouched 1900 | * Necessary so that we can reliably check which functions are present in 1901 | * user code 1902 | * 1903 | * @param stringWithLiterals 1904 | * The String to remove String/char literals from 1905 | * @return String stripped of literals 1906 | */ 1907 | private static String removeLiterals(String stringWithLiterals) { 1908 | /* string -> char array, so we can analyze one char at a time */ 1909 | char[] literalsChars = stringWithLiterals.toCharArray(); 1910 | 1911 | /* variable to hold our position */ 1912 | int index = 0; 1913 | 1914 | /* variable to hold our final String */ 1915 | String noLiterals = ""; 1916 | 1917 | /* go through each character */ 1918 | while (index < literalsChars.length) { 1919 | /* check for a string literal */ 1920 | if (literalsChars[index] == '"') { 1921 | index++; 1922 | while (literalsChars[index] != '"') { 1923 | if (literalsChars[index] == '\\') { 1924 | index++; 1925 | } 1926 | index++; 1927 | } 1928 | index++; 1929 | } 1930 | 1931 | /* check for character literals */ 1932 | else if (literalsChars[index] == '\'') { 1933 | index++; 1934 | while (literalsChars[index] != '\'') { 1935 | if (literalsChars[index] == '\\') { 1936 | index++; 1937 | } 1938 | index++; 1939 | } 1940 | index++; 1941 | } 1942 | 1943 | /* check for the start of a comment */ 1944 | else if (literalsChars[index] == '/') { 1945 | noLiterals = noLiterals + String.valueOf(literalsChars[index]); 1946 | index++; 1947 | 1948 | /* if it's this // kind of comment */ 1949 | if (literalsChars[index] == '/') { 1950 | noLiterals = noLiterals 1951 | + String.valueOf(literalsChars[index]); 1952 | index++; 1953 | while (literalsChars[index] != '\n') { 1954 | noLiterals = noLiterals 1955 | + String.valueOf(literalsChars[index]); 1956 | index++; 1957 | } 1958 | noLiterals = noLiterals + "\n"; 1959 | index++; 1960 | } 1961 | /* if it's this /* kind of comment */ 1962 | else if (literalsChars[index] == '*') { 1963 | noLiterals = noLiterals 1964 | + String.valueOf(literalsChars[index]); 1965 | index++; 1966 | boolean done = false; 1967 | while (done == false) { 1968 | noLiterals = noLiterals 1969 | + String.valueOf(literalsChars[index]); 1970 | /* maybe it's finishing... */ 1971 | if (literalsChars[index] == '*') { 1972 | index++; 1973 | noLiterals = noLiterals 1974 | + String.valueOf(literalsChars[index]); 1975 | if (literalsChars[index] == '/') { 1976 | done = true; 1977 | } 1978 | index++; 1979 | } else { 1980 | index++; 1981 | } 1982 | } 1983 | } 1984 | /* if it's not even a comment */ 1985 | else { 1986 | noLiterals = noLiterals + "/"; 1987 | } 1988 | } 1989 | 1990 | /* if there's no doubt just add it on */ 1991 | else { 1992 | noLiterals = noLiterals + String.valueOf(literalsChars[index]); 1993 | index++; 1994 | } 1995 | } 1996 | return noLiterals; 1997 | } 1998 | 1999 | /** 2000 | * Reads file contents (from a resource inside the JAR) into string 2001 | * 2002 | * @param resourcePath 2003 | * the path to the resource within the JAR file 2004 | * @return file contents as string 2005 | */ 2006 | private static String resourceRead(String resourcePath) { 2007 | try { 2008 | InputStream inputStream = Thread.currentThread() 2009 | .getContextClassLoader().getResourceAsStream(resourcePath); 2010 | BufferedReader bufferedReader = new BufferedReader( 2011 | new InputStreamReader(inputStream, "UTF-8")); 2012 | StringBuilder stringBuilder = new StringBuilder(); 2013 | String line = bufferedReader.readLine(); 2014 | while (line != null) { 2015 | stringBuilder.append(line); 2016 | if (line != null) { 2017 | stringBuilder.append("\n"); 2018 | } 2019 | line = bufferedReader.readLine(); 2020 | } 2021 | return stringBuilder.toString(); 2022 | } catch (Exception e) { 2023 | System.out 2024 | .println("Compiler encountered an error reading JAR resource \"" 2025 | + resourcePath 2026 | + "\" -- the JAR file may be corrupt."); 2027 | e.printStackTrace(); 2028 | System.exit(1); 2029 | return ""; 2030 | } 2031 | } 2032 | 2033 | /** 2034 | * Reads file contents into a string 2035 | * 2036 | * @param filePath 2037 | * path of file to read 2038 | * @return file contents as string 2039 | */ 2040 | private static String fileRead(String filePath) { 2041 | try { 2042 | BufferedReader br = new BufferedReader(new FileReader(filePath)); 2043 | StringBuilder data = new StringBuilder(); 2044 | String line = br.readLine(); 2045 | while (line != null) { 2046 | data.append(line); 2047 | data.append('\n'); 2048 | line = br.readLine(); 2049 | } 2050 | String fileData = data.toString(); 2051 | br.close(); 2052 | return fileData; 2053 | } catch (Exception e) { 2054 | System.out.println("Compiler encountered an error reading file \"" 2055 | + filePath + "\""); 2056 | e.printStackTrace(); 2057 | System.exit(1); 2058 | return "null"; 2059 | } 2060 | } 2061 | 2062 | /** 2063 | * Write data to a file 2064 | * 2065 | * @param fPath 2066 | * the file to write to 2067 | * @param data 2068 | * the data to write to file 2069 | * @return true or false with success/failure 2070 | */ 2071 | private static boolean fileWrite(String fPath, String data) { 2072 | BufferedWriter bufferedWriter = null; 2073 | boolean encounteredError = false; 2074 | try { 2075 | File myFile = new File(fPath); 2076 | if (!myFile.exists()) 2077 | myFile.createNewFile(); 2078 | Writer writer = new FileWriter(myFile); 2079 | bufferedWriter = new BufferedWriter(writer); 2080 | bufferedWriter.write(data); 2081 | return true; 2082 | } catch (IOException e) { 2083 | System.out 2084 | .println("Compiler encountered an error writing to file \"" 2085 | + fPath + "\""); 2086 | e.printStackTrace(); 2087 | encounteredError = true; 2088 | } finally { 2089 | /* if there's an error try to close the file if we can */ 2090 | try { 2091 | if (bufferedWriter != null) 2092 | bufferedWriter.close(); 2093 | } catch (Exception ex) { 2094 | 2095 | } 2096 | if (encounteredError) 2097 | System.exit(1); 2098 | } 2099 | return false; 2100 | } 2101 | 2102 | /** 2103 | * Remove a directory and its contents. 2104 | * 2105 | * @param directory 2106 | * File object representing directory to remove 2107 | * @return true on success, false on failure 2108 | */ 2109 | private static boolean deleteDirectory(File directory) { 2110 | if (directory == null) 2111 | return false; 2112 | if (!directory.exists()) 2113 | return true; 2114 | if (!directory.isDirectory()) 2115 | return false; 2116 | 2117 | String[] list = directory.list(); 2118 | 2119 | // Some JVMs return null for File.list() when the 2120 | // directory is empty. 2121 | if (list != null) { 2122 | for (int i = 0; i < list.length; i++) { 2123 | File entry = new File(directory, list[i]); 2124 | if (entry.isDirectory()) { 2125 | if (!deleteDirectory(entry)) 2126 | return false; 2127 | } else { 2128 | if (!entry.delete()) 2129 | return false; 2130 | } 2131 | } 2132 | } 2133 | return directory.delete(); 2134 | } 2135 | 2136 | /** 2137 | * Check to see if a user's import statement is redundant 2138 | * 2139 | * @param userImport 2140 | * the user's import statement 2141 | * @param generatedImports 2142 | * the generated list of imports 2143 | * @return true if the userImport is a line inside of generatedImports 2144 | */ 2145 | private static boolean alreadyImported(String userImport, 2146 | String generatedImports) { 2147 | for (String line : generatedImports.split("\n")) { 2148 | if (line.equals(userImport)) 2149 | return true; 2150 | } 2151 | return false; 2152 | } 2153 | 2154 | /** 2155 | * Indent each line of a string with one tab 2156 | * 2157 | * @param x 2158 | * the string to indent 2159 | * @return indented string 2160 | */ 2161 | private static String indent(String x) { 2162 | return indent(x, 1); 2163 | } 2164 | 2165 | /** 2166 | * Indent each line of a string with n tabs 2167 | * 2168 | * @param x 2169 | * String to indent 2170 | * @param n 2171 | * The number of tabs to indent by 2172 | * @return indented string 2173 | */ 2174 | private static String indent(String x, int n) { 2175 | String indentedString = ""; 2176 | String indent = ""; 2177 | for (int i = 0; i < n; i++) 2178 | indent = indent + "\t"; 2179 | for (String line : x.split("\n")) 2180 | indentedString = indentedString + indent + line + "\n"; 2181 | return indentedString; 2182 | } 2183 | 2184 | /** 2185 | * Print a message to the terminal if verbose is set to true 2186 | * 2187 | * @param message 2188 | * string to print 2189 | * @param newLines 2190 | * amount of newline characters to print at end of string 2191 | */ 2192 | private static void verbose(String message, int newLines) { 2193 | if (verbose) { 2194 | System.out.print(message); 2195 | for (int i = 0; i < newLines; i++) 2196 | System.out.print("\n"); 2197 | } 2198 | } 2199 | 2200 | /** 2201 | * Print a message to the terminal if verbose is set to true 2202 | * 2203 | * @param message 2204 | * string to print 2205 | */ 2206 | private static void verbose(String message) { 2207 | verbose(message, 1); 2208 | } 2209 | 2210 | } 2211 | -------------------------------------------------------------------------------- /src/test/java/com/automation/javauto/test/JavautoTest.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.test; 2 | 3 | import static org.assertj.core.api.StrictAssertions.assertThat; 4 | import static org.assertj.core.api.StrictAssertions.fail; 5 | import static org.assertj.core.api.Assertions.*; 6 | 7 | import java.awt.MouseInfo; 8 | import java.io.File; 9 | import java.io.FileNotFoundException; 10 | import java.io.PrintWriter; 11 | import java.io.UnsupportedEncodingException; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import org.junit.Test; 17 | 18 | import com.automation.javauto.Javauto; 19 | 20 | /** 21 | * Some test for the {@link Javauto} class. 22 | * 23 | * @author henry.tejera 24 | * 25 | */ 26 | public class JavautoTest { 27 | 28 | public final String SEP = File.separator; 29 | public final String TEST_RESOURCES_PATH = "src" + SEP + "test" + SEP 30 | + "resources" + SEP; 31 | public final String TEST_FILE = "fermat.txt"; 32 | 33 | @Test 34 | public void testGetAndSetSpeed() { 35 | Javauto javauto = new Javauto(); 36 | double defaultSpeed = 0.95D; 37 | double newSpeed = 0.5D; 38 | double maxLimitSpeed = 1.0D; 39 | double minLimitSpeed = 0.0D; 40 | double upLimitSpeed = 1.1D; 41 | double underLimitSpeed = -1.0D; 42 | 43 | assertThat(javauto.getSpeed()).isEqualTo(defaultSpeed); 44 | 45 | javauto.setSpeed(newSpeed); 46 | assertThat(javauto.getSpeed()).isEqualTo(newSpeed); 47 | 48 | javauto.setSpeed(maxLimitSpeed); 49 | assertThat(javauto.getSpeed()).isEqualTo(maxLimitSpeed); 50 | 51 | javauto.setSpeed(minLimitSpeed); 52 | assertThat(javauto.getSpeed()).isEqualTo(minLimitSpeed); 53 | 54 | javauto.setSpeed(upLimitSpeed); 55 | assertThat(javauto.getSpeed()).isEqualTo(maxLimitSpeed); 56 | 57 | javauto.setSpeed(underLimitSpeed); 58 | assertThat(javauto.getSpeed()).isEqualTo(minLimitSpeed); 59 | } 60 | 61 | @Test() 62 | public void testKeyDownShouldBeReturnRuntimeExceptionWithBadKey() { 63 | Javauto javauto = new Javauto(); 64 | String badKey = "{INVALIDENTER}"; 65 | 66 | try { 67 | javauto.keyDown(badKey); 68 | fail("RuntimeException expected because the Key is invalid."); 69 | } catch (RuntimeException e) { 70 | assertThat(e).hasMessage("Cannot type " + badKey); 71 | } 72 | } 73 | 74 | @Test() 75 | public void testKeyDownShouldBeReturnRuntimeExceptionWithInvalidKeyCode() { 76 | Javauto javauto = new Javauto(); 77 | int badKeyCode = 0; 78 | 79 | try { 80 | javauto.keyDown(badKeyCode); 81 | fail("RuntimeException expected because the keycode is not a valid key."); 82 | } catch (RuntimeException e) { 83 | assertThat(e); 84 | } 85 | } 86 | 87 | @Test() 88 | public void testKeyUpShouldBeReturnRuntimeExceptionWithBadKey() { 89 | Javauto javauto = new Javauto(); 90 | String badKey = "{INVALIDENTER}"; 91 | 92 | try { 93 | javauto.keyUp(badKey); 94 | fail("RuntimeException expected because the Key is invalid."); 95 | } catch (RuntimeException e) { 96 | assertThat(e); 97 | } 98 | } 99 | 100 | @Test() 101 | public void testKeyUpShouldBeReturnRuntimeExceptionWithInvalidKeyCode() { 102 | Javauto javauto = new Javauto(); 103 | int badKey = 0; 104 | 105 | try { 106 | javauto.keyUp(badKey); 107 | fail("RuntimeException expected because the keycode is not a valid key."); 108 | } catch (RuntimeException e) { 109 | assertThat(e); 110 | } 111 | } 112 | 113 | @Test() 114 | public void testKeyPressShouldBeReturnRuntimeExceptionWithInvalidKeyCode() { 115 | Javauto javauto = new Javauto(); 116 | int badKey = 0; 117 | 118 | try { 119 | javauto.keyPress(badKey); 120 | fail("RuntimeException expected because the keycode is not a valid key."); 121 | } catch (RuntimeException e) { 122 | assertThat(e); 123 | } 124 | } 125 | 126 | @Test 127 | public void testSleephouldBeReturnRuntimeExceptionWithInvalidTimeout() { 128 | Javauto javauto = new Javauto(); 129 | int timeout = 600001; 130 | 131 | try { 132 | javauto.sleep(timeout); 133 | fail("RuntimeException expected because the timeout is not a valid timeout."); 134 | } catch (RuntimeException e) { 135 | assertThat(e); 136 | } 137 | } 138 | 139 | @Test 140 | // Do not move your mouse :). 141 | public void testMouseMove() throws InterruptedException { 142 | Javauto javauto = new Javauto(); 143 | 144 | // if x is larger than y. 145 | int x1 = 40; 146 | int y1 = 10; 147 | javauto.mouseMove(x1, y1); 148 | TimeUnit.SECONDS.sleep(1); 149 | 150 | int actualX = MouseInfo.getPointerInfo().getLocation().x; 151 | int actualY = MouseInfo.getPointerInfo().getLocation().y; 152 | 153 | assertThat(x1).isEqualTo(actualX); 154 | assertThat(y1).isEqualTo(actualY); 155 | 156 | // if y is larger than x. 157 | int x2 = 10; 158 | int y2 = 40; 159 | javauto.mouseMove(x2, y2); 160 | TimeUnit.SECONDS.sleep(1); 161 | 162 | actualX = MouseInfo.getPointerInfo().getLocation().x; 163 | actualY = MouseInfo.getPointerInfo().getLocation().y; 164 | 165 | assertThat(x2).isEqualTo(actualX); 166 | assertThat(y2).isEqualTo(actualY); 167 | 168 | // equals. 169 | int x3 = 40; 170 | int y3 = 40; 171 | javauto.mouseMove(x3, y3); 172 | TimeUnit.SECONDS.sleep(1); 173 | 174 | actualX = MouseInfo.getPointerInfo().getLocation().x; 175 | actualY = MouseInfo.getPointerInfo().getLocation().y; 176 | 177 | assertThat(x3).isEqualTo(actualX); 178 | assertThat(y3).isEqualTo(actualY); 179 | } 180 | 181 | @Test 182 | public void testMouseClickStringIntInt() throws InterruptedException { 183 | Javauto javauto = new Javauto(); 184 | int locationX = (javauto.SCREEN_HEIGHT / 2) - (600 / 2); 185 | int locationY = (javauto.SCREEN_WIDTH / 2) - (800 / 2); 186 | 187 | TestPanel panel = new TestPanel(800, 600, locationX, locationY); 188 | javauto.setSpeed(0.5D); 189 | 190 | // Left 191 | int x = locationX + 120; 192 | int y = locationY + 120; 193 | javauto.mouseClick("left", x, y); 194 | TimeUnit.SECONDS.sleep(2); 195 | 196 | int actualX = MouseInfo.getPointerInfo().getLocation().x; 197 | int actualY = MouseInfo.getPointerInfo().getLocation().y; 198 | 199 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("left"); 200 | assertThat(x).isEqualTo(actualX); 201 | assertThat(y).isEqualTo(actualY); 202 | 203 | // middle 204 | x = locationX + 130; 205 | y = locationY + 130; 206 | javauto.mouseMove(x, y); 207 | javauto.mouseClick("middle"); 208 | TimeUnit.SECONDS.sleep(2); 209 | 210 | actualX = MouseInfo.getPointerInfo().getLocation().x; 211 | actualY = MouseInfo.getPointerInfo().getLocation().y; 212 | 213 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("middle"); 214 | assertThat(x).isEqualTo(actualX); 215 | assertThat(y).isEqualTo(actualY); 216 | 217 | // right 218 | x = locationX + 140; 219 | y = locationY + 140; 220 | javauto.mouseMove(x, y); 221 | javauto.mouseClick("right"); 222 | TimeUnit.SECONDS.sleep(2); 223 | 224 | actualX = MouseInfo.getPointerInfo().getLocation().x; 225 | actualY = MouseInfo.getPointerInfo().getLocation().y; 226 | 227 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("right"); 228 | assertThat(x).isEqualTo(actualX); 229 | assertThat(y).isEqualTo(actualY); 230 | 231 | // Invalid 232 | x = locationX + 150; 233 | y = locationY + 150; 234 | javauto.mouseMove(x, y); 235 | javauto.mouseClick("INVALID"); 236 | TimeUnit.SECONDS.sleep(2); 237 | 238 | actualX = MouseInfo.getPointerInfo().getLocation().x; 239 | actualY = MouseInfo.getPointerInfo().getLocation().y; 240 | 241 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("right"); 242 | assertThat(x).isEqualTo(actualX); 243 | assertThat(y).isEqualTo(actualY); 244 | } 245 | 246 | @Test 247 | public void testMouseClickString() throws InterruptedException { 248 | Javauto javauto = new Javauto(); 249 | int locationX = (javauto.SCREEN_HEIGHT / 2) - (600 / 2); 250 | int locationY = (javauto.SCREEN_WIDTH / 2) - (800 / 2); 251 | 252 | TestPanel panel = new TestPanel(800, 600, locationX, locationY); 253 | javauto.setSpeed(0.5D); 254 | 255 | // Left 256 | javauto.mouseMove(locationX + 120, locationY + 120); 257 | javauto.mouseClick("left"); 258 | TimeUnit.SECONDS.sleep(2); 259 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("left"); 260 | 261 | // middle 262 | javauto.mouseMove(locationX + 120, locationY + 120); 263 | javauto.mouseClick("middle"); 264 | TimeUnit.SECONDS.sleep(2); 265 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("middle"); 266 | 267 | // right 268 | javauto.mouseMove(locationX + 120, locationY + 120); 269 | javauto.mouseClick("right"); 270 | TimeUnit.SECONDS.sleep(2); 271 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("right"); 272 | 273 | // Nothing 274 | javauto.mouseMove(locationX + 120, locationY + 120); 275 | javauto.mouseClick("INVALID"); 276 | TimeUnit.SECONDS.sleep(2); 277 | assertThat(panel.getClickedButton()).isEqualToIgnoringCase("right"); 278 | } 279 | 280 | @Test 281 | public void testToDoubleString() { 282 | Javauto javauto = new Javauto(); 283 | assertThat(javauto.toDouble("0.0")).isEqualTo(0.0D); 284 | } 285 | 286 | @Test 287 | public void testToDoubleChar() { 288 | Javauto javauto = new Javauto(); 289 | char c = "0".charAt(0); 290 | assertThat(javauto.toDouble(c)).isEqualTo(0.0D); 291 | } 292 | 293 | @Test 294 | public void testToDoubleBoolean() { 295 | Javauto javauto = new Javauto(); 296 | assertThat(javauto.toDouble(false)).isEqualTo(0.0D); 297 | } 298 | 299 | @Test 300 | public void testToDoubleInt() { 301 | Javauto javauto = new Javauto(); 302 | assertThat(javauto.toDouble(1)).isEqualTo(1.0D); 303 | } 304 | 305 | @Test 306 | public void testToDoubleLong() { 307 | Javauto javauto = new Javauto(); 308 | assertThat(javauto.toDouble(new Long(198546L))).isEqualTo(198546.0D); 309 | } 310 | 311 | @Test 312 | public void testToDoubleShort() { 313 | Javauto javauto = new Javauto(); 314 | assertThat(javauto.toDouble(new Short("10"))).isEqualTo(10.0D); 315 | } 316 | 317 | @Test 318 | public void testToDoubleFloat() { 319 | Javauto javauto = new Javauto(); 320 | float f = 1F; 321 | assertThat(javauto.toDouble(f)).isEqualTo(1.0D); 322 | } 323 | 324 | @Test 325 | public void testToDoubleByte() { 326 | Javauto javauto = new Javauto(); 327 | byte b = 10; 328 | assertThat(javauto.toDouble(b)).isEqualTo(10.0D); 329 | } 330 | 331 | @Test 332 | public void testToFloatString() { 333 | Javauto javauto = new Javauto(); 334 | assertThat(javauto.toFloat("10")).isEqualTo(10.0F); 335 | } 336 | 337 | @Test 338 | public void testToFloatChar() { 339 | Javauto javauto = new Javauto(); 340 | char c = "0".charAt(0); 341 | assertThat(javauto.toFloat(c)).isEqualTo(0.0F); 342 | } 343 | 344 | @Test 345 | public void testToFloatBoolean() { 346 | Javauto javauto = new Javauto(); 347 | assertThat(javauto.toFloat(true)).isEqualTo(1.0F); 348 | } 349 | 350 | @Test 351 | public void testToFloatInt() { 352 | Javauto javauto = new Javauto(); 353 | assertThat(javauto.toFloat(1)).isEqualTo(1.0F); 354 | } 355 | 356 | @Test 357 | public void testToFloatLong() { 358 | Javauto javauto = new Javauto(); 359 | assertThat(javauto.toFloat(new Long(198546L))).isEqualTo(198546.0F); 360 | } 361 | 362 | @Test 363 | public void testToFloatShort() { 364 | Javauto javauto = new Javauto(); 365 | assertThat(javauto.toFloat(new Short("10"))).isEqualTo(10.0F); 366 | } 367 | 368 | @Test 369 | public void testToFloatDouble() { 370 | Javauto javauto = new Javauto(); 371 | assertThat(javauto.toFloat(new Double(10D))).isEqualTo(10.0F); 372 | } 373 | 374 | @Test 375 | public void testToFloatByte() { 376 | Javauto javauto = new Javauto(); 377 | byte b = 10; 378 | assertThat(javauto.toFloat(b)).isEqualTo(10.0F); 379 | } 380 | 381 | @Test 382 | public void testToIntString() { 383 | Javauto javauto = new Javauto(); 384 | assertThat(javauto.toInt("1831")).isEqualTo(1831); 385 | } 386 | 387 | @Test 388 | public void testToIntChar() { 389 | Javauto javauto = new Javauto(); 390 | char c = "1".charAt(0); 391 | assertThat(javauto.toInt(c)).isEqualTo(1); 392 | } 393 | 394 | @Test 395 | public void testToIntBoolean() { 396 | Javauto javauto = new Javauto(); 397 | assertThat(javauto.toInt(true)).isEqualTo(1); 398 | } 399 | 400 | @Test 401 | public void testToIntLong() { 402 | Javauto javauto = new Javauto(); 403 | assertThat(javauto.toInt(new Long(198546L))).isEqualTo(198546); 404 | } 405 | 406 | @Test 407 | public void testToIntShort() { 408 | Javauto javauto = new Javauto(); 409 | assertThat(javauto.toInt(new Short("10"))).isEqualTo(10); 410 | } 411 | 412 | @Test 413 | public void testToIntFloat() { 414 | Javauto javauto = new Javauto(); 415 | float f = 1F; 416 | assertThat(javauto.toInt(f)).isEqualTo(1); 417 | } 418 | 419 | @Test 420 | public void testToIntDouble() { 421 | Javauto javauto = new Javauto(); 422 | assertThat(javauto.toInt(1.0D)).isEqualTo(1); 423 | } 424 | 425 | @Test 426 | public void testToIntByte() { 427 | Javauto javauto = new Javauto(); 428 | byte b = 10; 429 | assertThat(javauto.toInt(b)).isEqualTo(10); 430 | } 431 | 432 | @Test 433 | public void testToCharString() { 434 | Javauto javauto = new Javauto(); 435 | assertThat(javauto.toChar("Fermat")).isEqualTo('F'); 436 | } 437 | 438 | @Test 439 | public void testToStringChar() { 440 | Javauto javauto = new Javauto(); 441 | char c = "1".charAt(0); 442 | assertThat(javauto.toString(c)).isEqualTo("1"); 443 | } 444 | 445 | @Test 446 | public void testToStringBoolean() { 447 | Javauto javauto = new Javauto(); 448 | assertThat(javauto.toString(true)).isEqualTo("true"); 449 | } 450 | 451 | @Test 452 | public void testToStringInt() { 453 | Javauto javauto = new Javauto(); 454 | assertThat(javauto.toString(1)).isEqualTo("1"); 455 | } 456 | 457 | @Test 458 | public void testToStringLong() { 459 | Javauto javauto = new Javauto(); 460 | assertThat(javauto.toString(new Long(198546L))).isEqualTo("198546"); 461 | } 462 | 463 | @Test 464 | public void testToStringShort() { 465 | Javauto javauto = new Javauto(); 466 | assertThat(javauto.toString(new Short("10"))).isEqualTo("10"); 467 | } 468 | 469 | @Test 470 | public void testToStringFloat() { 471 | Javauto javauto = new Javauto(); 472 | float f = 1F; 473 | assertThat(javauto.toString(f)).isEqualTo("1.0"); 474 | } 475 | 476 | @Test 477 | public void testToStringDouble() { 478 | Javauto javauto = new Javauto(); 479 | assertThat(javauto.toString(1.0D)).isEqualTo("1.0"); 480 | } 481 | 482 | @Test 483 | public void testToStringByte() { 484 | Javauto javauto = new Javauto(); 485 | byte b = 10; 486 | assertThat(javauto.toString(b)).isEqualTo("10"); 487 | } 488 | 489 | @Test 490 | public void testFileExists() { 491 | Javauto javauto = new Javauto(); 492 | String file = TEST_RESOURCES_PATH + TEST_FILE; 493 | assertThat(javauto.fileExists(file)).isEqualTo(true); 494 | } 495 | 496 | @Test 497 | public void testIsFile() { 498 | Javauto javauto = new Javauto(); 499 | String file = TEST_RESOURCES_PATH + TEST_FILE; 500 | assertThat(javauto.isFile(file)).isEqualTo(true); 501 | } 502 | 503 | @Test 504 | public void testFileDelete() throws FileNotFoundException, 505 | UnsupportedEncodingException { 506 | Javauto javauto = new Javauto(); 507 | 508 | String file = TEST_RESOURCES_PATH + "lagrange"; 509 | PrintWriter writer = new PrintWriter(file, "UTF-8"); 510 | writer.println("The first line"); 511 | writer.println("The second line"); 512 | writer.close(); 513 | 514 | javauto.fileDelete(file); 515 | assertThat(new File(file)).doesNotExist(); 516 | 517 | } 518 | 519 | @Test 520 | public void testRmDir() { 521 | Javauto javauto = new Javauto(); 522 | String dir = TEST_RESOURCES_PATH + "DIR"; 523 | new File(dir).mkdirs(); 524 | 525 | javauto.rmDir(dir); 526 | assertThat(new File(dir)).doesNotExist(); 527 | } 528 | 529 | @Test 530 | public void testMkDir() { 531 | Javauto javauto = new Javauto(); 532 | String dir = TEST_RESOURCES_PATH + "NEW"; 533 | javauto.mkDir(dir); 534 | 535 | File theDir = new File(dir); 536 | assertThat(theDir).exists().isDirectory(); 537 | theDir.delete(); 538 | } 539 | 540 | @Test 541 | public void testFileCreate() { 542 | Javauto javauto = new Javauto(); 543 | String filePath = TEST_RESOURCES_PATH + "evariste.txt"; 544 | javauto.fileCreate(filePath); 545 | 546 | File file = new File(filePath); 547 | assertThat(file).exists().isFile(); 548 | file.delete(); 549 | } 550 | 551 | @Test 552 | public void testFileGetPath() { 553 | Javauto javauto = new Javauto(); 554 | String filePath = TEST_RESOURCES_PATH + TEST_FILE; 555 | File file = new File(filePath); 556 | assertThat(javauto.fileGetPath(filePath)).isEqualToIgnoringCase( 557 | file.getAbsolutePath()); 558 | } 559 | 560 | @Test 561 | public void testFileGetName() { 562 | Javauto javauto = new Javauto(); 563 | String filePath = TEST_RESOURCES_PATH + TEST_FILE; 564 | File file = new File(filePath); 565 | assertThat(javauto.fileGetName(filePath)).isEqualToIgnoringCase( 566 | file.getName()); 567 | } 568 | 569 | @Test 570 | public void testIsDirectory() { 571 | Javauto javauto = new Javauto(); 572 | assertThat(javauto.isDirectory(TEST_RESOURCES_PATH)).isEqualTo(true); 573 | assertThat(javauto.isDirectory(TEST_RESOURCES_PATH + TEST_FILE)) 574 | .isEqualTo(false); 575 | assertThat(javauto.isDirectory("NO")).isEqualTo(false); 576 | } 577 | 578 | @Test 579 | public void testFileRead() { 580 | Javauto javauto = new Javauto(); 581 | String path = TEST_RESOURCES_PATH + TEST_FILE; 582 | assertThat(javauto.fileRead(path)).isEqualToIgnoringCase( 583 | "France Toulouse"); 584 | } 585 | 586 | @Test 587 | public void testFileWrite() { 588 | Javauto javauto = new Javauto(); 589 | String path = TEST_RESOURCES_PATH + "poincare.txt"; 590 | String content = "France"; 591 | 592 | javauto.fileWrite(path, content); 593 | File file = new File(path); 594 | assertThat(contentOf(file)).contains(content); 595 | file.delete(); 596 | } 597 | 598 | @Test 599 | public void testFileAppend() throws FileNotFoundException, 600 | UnsupportedEncodingException { 601 | Javauto javauto = new Javauto(); 602 | 603 | String filePath = TEST_RESOURCES_PATH + "massera.txt"; 604 | String content = "2"; 605 | PrintWriter writer = new PrintWriter(filePath, "UTF-8"); 606 | writer.println("1"); 607 | writer.close(); 608 | 609 | javauto.fileAppend(filePath, content); 610 | File file = new File(filePath); 611 | assertThat(contentOf(file)).contains(content); 612 | file.delete(); 613 | } 614 | 615 | @Test 616 | public void testFileList() { 617 | Javauto javauto = new Javauto(); 618 | String[] files = javauto.fileList(TEST_RESOURCES_PATH); 619 | assertThat(files.length).isGreaterThan(0); 620 | } 621 | 622 | @Test 623 | public void testClipboardPutAndGet() { 624 | Javauto javauto = new Javauto(); 625 | String content = "buttner"; 626 | javauto.clipboardPut(content); 627 | assertThat(javauto.clipboardGet()).isEqualTo(content); 628 | } 629 | 630 | @Test 631 | public void testHttpGet() { 632 | Javauto javauto = new Javauto(); 633 | String urlHttp = "https://en.wikipedia.org/wiki/Rudolf_Carnap"; 634 | String urlHttps = "https://en.wikipedia.org/wiki/Alonzo_Church"; 635 | 636 | assertThat(javauto.httpGet(urlHttp)).contains("Logical positivism"); 637 | assertThat(javauto.httpGet(urlHttps)).contains("lambda"); 638 | } 639 | 640 | @Test 641 | public void testHttpGetShouldBeReturnEmpty() { 642 | Javauto javauto = new Javauto(); 643 | String url = "http://noerterfasdpeor.com"; 644 | assertThat(javauto.httpGet(url)).isEmpty(); 645 | } 646 | 647 | @Test 648 | public void testGetPage() { 649 | Javauto javauto = new Javauto(); 650 | String urlHttp = "https://en.wikipedia.org/wiki/Gary_R._Mar"; 651 | String urlHttps = "https://en.wikipedia.org/wiki/Raymond_Smullyan"; 652 | 653 | assertThat(javauto.getPage(urlHttp)).contains( 654 | "Philosophy of Mathematics"); 655 | assertThat(javauto.getPage(urlHttps)) 656 | .contains("American mathematician"); 657 | } 658 | 659 | @Test 660 | public void testGetPageShouldBeReturnError() { 661 | Javauto javauto = new Javauto(); 662 | String urlHttp = "https://seguad/logical/positivism"; 663 | assertThat(javauto.getPage(urlHttp)).contains("Error"); 664 | } 665 | 666 | @Test 667 | public void testHttpPost() { 668 | Javauto javauto = new Javauto(); 669 | String url = "https://posttestserver.com/post.php"; 670 | String[][] parameters = new String[][] { { "a", "1" }, { "b", "2" }, 671 | { "c", "3" } }; 672 | 673 | assertThat(javauto.httpPost(url, parameters)).contains( 674 | "Successfully dumped 3 post variables."); 675 | } 676 | 677 | @Test 678 | public void testJoin() { 679 | Javauto javauto = new Javauto(); 680 | String[] strArray = { "Jack Copeland", "Sebastian Guadagna" }; 681 | String delimiter = "|"; 682 | 683 | assertThat(javauto.join(delimiter, strArray)).isEqualToIgnoringCase( 684 | "Jack Copeland|Sebastian Guadagna"); 685 | } 686 | 687 | @Test 688 | public void testArrayAsList() { 689 | Javauto javauto = new Javauto(); 690 | String[] strArray = { "Jack Copeland", "Sebastian Gudagn" }; 691 | List expected = Arrays.asList(strArray); 692 | List theList = javauto.arrayAsList(strArray); 693 | 694 | assertThat(theList).isEqualToComparingFieldByField(expected); 695 | } 696 | 697 | @Test 698 | public void testArrayBinarySearchByte() { 699 | Javauto javauto = new Javauto(); 700 | byte searchVal = 35; 701 | byte arr[] = { 10, 12, 34, searchVal, 5 }; 702 | int index = javauto.arrayBinarySearch(arr, searchVal); 703 | 704 | assertThat(index).isEqualTo(4); 705 | } 706 | 707 | @Test 708 | public void testArrayBinarySearchChar() { 709 | Javauto javauto = new Javauto(); 710 | char searchVal = 'c'; 711 | char arr[] = { 'a', 'c', 'b', 'e', 'd' }; 712 | int index = javauto.arrayBinarySearch(arr, searchVal); 713 | 714 | assertThat(index).isEqualTo(2); 715 | } 716 | 717 | @Test 718 | public void testArrayBinarySearchDouble() { 719 | Javauto javauto = new Javauto(); 720 | double searchVal = 4.6; 721 | double arr[] = { 5.4, 49.2, 9.2, 35.4, 4.6 }; 722 | int index = javauto.arrayBinarySearch(arr, searchVal); 723 | 724 | assertThat(index).isEqualTo(0); 725 | } 726 | 727 | @Test 728 | public void testArrayBinarySearchFloat() { 729 | Javauto javauto = new Javauto(); 730 | float searchVal = 42.9f; 731 | float arr[] = { 5.2f, 46.1f, 42.9f, 22.3f }; 732 | int index = javauto.arrayBinarySearch(arr, searchVal); 733 | 734 | assertThat(index).isEqualTo(2); 735 | } 736 | 737 | @Test 738 | public void testArrayBinarySearchInt() { 739 | Javauto javauto = new Javauto(); 740 | int searchVal = 5; 741 | int arr[] = { 30, 20, 5, 12, 55 }; 742 | int index = javauto.arrayBinarySearch(arr, searchVal); 743 | 744 | assertThat(index).isEqualTo(0); 745 | } 746 | 747 | @Test 748 | public void testArrayBinarySearchLong() { 749 | Javauto javauto = new Javauto(); 750 | long searchVal = 46464; 751 | long arr[] = { 56, 46464, 3342, 232, 3445 }; 752 | int index = javauto.arrayBinarySearch(arr, searchVal); 753 | 754 | assertThat(index).isEqualTo(4); 755 | } 756 | 757 | @Test 758 | public void testArrayBinarySearchShort() { 759 | Javauto javauto = new Javauto(); 760 | short searchVal = 52; 761 | short arr[] = { 5, 2, 15, 52, 10 }; 762 | int index = javauto.arrayBinarySearch(arr, searchVal); 763 | 764 | assertThat(index).isEqualTo(4); 765 | } 766 | 767 | @Test 768 | public void testArrayCopyOfBoolean() { 769 | Javauto javauto = new Javauto(); 770 | boolean[] a1 = new boolean[] { true, false }; 771 | boolean[] a2 = javauto.arrayCopyOf(a1, 4); 772 | 773 | assertThat(a2).hasSize(4).contains(true, atIndex(0)) 774 | .contains(false, atIndex(1)).contains(false, atIndex(2)) 775 | .contains(false, atIndex(3)); 776 | } 777 | 778 | @Test 779 | public void testArrayCopyOfBooleanShouldBeReturnRuntimeExceptionWithNegativeLength() { 780 | Javauto javauto = new Javauto(); 781 | boolean[] a1 = new boolean[] { true, false }; 782 | 783 | try { 784 | javauto.arrayCopyOf(a1, -1); 785 | fail("RuntimeException expected because the new length is negative."); 786 | } catch (RuntimeException e) { 787 | assertThat(e); 788 | } 789 | } 790 | 791 | @Test 792 | public void testArrayCopyOfBytes() { 793 | Javauto javauto = new Javauto(); 794 | byte[] a1 = new byte[] { 5, 62, 15 }; 795 | byte[] a2 = javauto.arrayCopyOf(a1, 4); 796 | 797 | assertThat(a2).hasSize(4).contains((byte) 5, atIndex(0)) 798 | .contains((byte) 62, atIndex(1)) 799 | .contains((byte) 15, atIndex(2)).contains((byte) 0, atIndex(3)); 800 | } 801 | 802 | @Test 803 | public void testArrayCopyOfBytesShouldBeReturnRuntimeExceptionWithNegativeLength() { 804 | Javauto javauto = new Javauto(); 805 | byte[] a1 = new byte[] { 5, 62, 15 }; 806 | 807 | try { 808 | javauto.arrayCopyOf(a1, -1); 809 | fail("RuntimeException expected because the new length is nagative."); 810 | } catch (RuntimeException e) { 811 | assertThat(e); 812 | } 813 | } 814 | 815 | @Test 816 | public void testArrayCopyOfChar() { 817 | Javauto javauto = new Javauto(); 818 | char[] a1 = new char[] { 'p', 's', 'r' }; 819 | char[] a2 = javauto.arrayCopyOf(a1, 4); 820 | 821 | assertThat(a2).hasSize(4).contains('p', atIndex(0)) 822 | .contains('s', atIndex(1)).contains('r', atIndex(2)); 823 | } 824 | 825 | @Test 826 | public void testArrayCopyOfCharShouldBeReturnRuntimeExceptionWithNegativeLength() { 827 | Javauto javauto = new Javauto(); 828 | char[] a1 = new char[] { 'p', 's', 'r' }; 829 | 830 | try { 831 | javauto.arrayCopyOf(a1, -1); 832 | fail("RuntimeException expected because the new length is negative."); 833 | } catch (RuntimeException e) { 834 | assertThat(e); 835 | } 836 | } 837 | 838 | @Test 839 | public void testArrayCopyOfDouble() { 840 | Javauto javauto = new Javauto(); 841 | double[] a1 = new double[] { 12.5, 3.2, 37.5 }; 842 | double[] a2 = javauto.arrayCopyOf(a1, 4); 843 | 844 | assertThat(a2).hasSize(4).contains(12.5, atIndex(0)) 845 | .contains(3.2, atIndex(1)).contains(37.5, atIndex(2)) 846 | .contains(0, atIndex(3)); 847 | } 848 | 849 | @Test 850 | public void testArrayCopyOfDoubleShouldBeReturnRuntimeExceptionWithNegativeLength() { 851 | Javauto javauto = new Javauto(); 852 | double[] a1 = new double[] { 12.5, 3.2, 37.5 }; 853 | 854 | try { 855 | javauto.arrayCopyOf(a1, -1); 856 | fail("RuntimeException expected because the new length is negative."); 857 | } catch (RuntimeException e) { 858 | assertThat(e); 859 | } 860 | } 861 | 862 | @Test 863 | public void testArrayCopyOfFloat() { 864 | Javauto javauto = new Javauto(); 865 | float[] a1 = new float[] { 10f, 32f, 25f }; 866 | float[] a2 = javauto.arrayCopyOf(a1, 4); 867 | 868 | assertThat(a2).hasSize(4).contains(10f, atIndex(0)) 869 | .contains(32f, atIndex(1)).contains(25f, atIndex(2)) 870 | .contains(0f, atIndex(3)); 871 | } 872 | 873 | @Test 874 | public void testArrayCopyOfFloatShouldBeReturnRuntimeExceptionWithNegativeLength() { 875 | Javauto javauto = new Javauto(); 876 | float[] a1 = new float[] { 10f, 32f, 25f }; 877 | 878 | try { 879 | javauto.arrayCopyOf(a1, -1); 880 | fail("RuntimeException expected because the new length is negative."); 881 | } catch (RuntimeException e) { 882 | assertThat(e); 883 | } 884 | } 885 | 886 | @Test 887 | public void testArrayCopyOfInt() { 888 | Javauto javauto = new Javauto(); 889 | int[] a1 = new int[] { 45, 32, 75 }; 890 | int[] a2 = javauto.arrayCopyOf(a1, 4); 891 | 892 | assertThat(a2).hasSize(4).contains(45, atIndex(0)) 893 | .contains(32, atIndex(1)).contains(75, atIndex(2)) 894 | .contains(0, atIndex(3)); 895 | } 896 | 897 | @Test 898 | public void testArrayCopyOfIntShouldBeReturnRuntimeExceptionWithNegativeLength() { 899 | Javauto javauto = new Javauto(); 900 | int[] a1 = new int[] { 45, 32, 75 }; 901 | 902 | try { 903 | javauto.arrayCopyOf(a1, -1); 904 | fail("RuntimeException expected because the new length is negative."); 905 | } catch (RuntimeException e) { 906 | assertThat(e); 907 | } 908 | } 909 | 910 | @Test 911 | public void testArrayCopyOfLong() { 912 | Javauto javauto = new Javauto(); 913 | long[] a1 = new long[] { 15, 10, 45 }; 914 | long[] a2 = javauto.arrayCopyOf(a1, 4); 915 | 916 | assertThat(a2).hasSize(4).contains(15, atIndex(0)) 917 | .contains(10, atIndex(1)).contains(45, atIndex(2)) 918 | .contains(0L, atIndex(3)); 919 | } 920 | 921 | @Test 922 | public void testArrayCopyOfLongShouldBeReturnRuntimeExceptionWithNegativeLength() { 923 | Javauto javauto = new Javauto(); 924 | long[] a1 = new long[] { 15, 10, 45 }; 925 | 926 | try { 927 | javauto.arrayCopyOf(a1, -1); 928 | fail("RuntimeException expected because the new length is negative."); 929 | } catch (RuntimeException e) { 930 | assertThat(e); 931 | } 932 | } 933 | 934 | @Test 935 | public void testArrayCopyOfShort() { 936 | Javauto javauto = new Javauto(); 937 | short[] a1 = new short[] { 15, 10, 45 }; 938 | short[] a2 = javauto.arrayCopyOf(a1, 4); 939 | 940 | assertThat(a2).hasSize(4).contains((short) 15, atIndex(0)) 941 | .contains((short) 10, atIndex(1)) 942 | .contains((short) 45, atIndex(2)) 943 | .contains((short) 0, atIndex(3)); 944 | } 945 | 946 | @Test 947 | public void testArrayCopyOfShortShouldBeReturnRuntimeExceptionWithNegativeLength() { 948 | Javauto javauto = new Javauto(); 949 | short[] a1 = new short[] { 15, 10, 45 }; 950 | 951 | try { 952 | javauto.arrayCopyOf(a1, -1); 953 | fail("RuntimeException expected because the new length is negative."); 954 | } catch (RuntimeException e) { 955 | assertThat(e); 956 | } 957 | } 958 | 959 | @Test 960 | public void testArraySortByte() { 961 | Javauto javauto = new Javauto(); 962 | byte[] a1 = { 10, 2, 7, 35 }; 963 | byte[] a2 = javauto.arraySort(a1); 964 | 965 | assertThat(a2).hasSize(4).contains((byte) 2, atIndex(0)) 966 | .contains((byte) 7, atIndex(1)).contains((byte) 10, atIndex(2)) 967 | .contains((byte) 35, atIndex(3)); 968 | } 969 | 970 | @Test 971 | public void testArraySortChar() { 972 | Javauto javauto = new Javauto(); 973 | char[] a1 = { 'r', 'q', 's', 'p' }; 974 | char[] a2 = javauto.arraySort(a1); 975 | 976 | assertThat(a2).hasSize(4).contains('p', atIndex(0)) 977 | .contains('q', atIndex(1)).contains('r', atIndex(2)) 978 | .contains('s', atIndex(3)); 979 | } 980 | 981 | @Test 982 | public void testArraySortDouble() { 983 | Javauto javauto = new Javauto(); 984 | double[] a1 = { 3.2, 1.2, 9.7 }; 985 | double[] a2 = javauto.arraySort(a1); 986 | 987 | assertThat(a2).hasSize(3).contains(1.2, atIndex(0)) 988 | .contains(3.2, atIndex(1)).contains(9.7, atIndex(2)); 989 | } 990 | 991 | @Test 992 | public void testArraySortFloat() { 993 | Javauto javauto = new Javauto(); 994 | float[] a1 = { 3.2f, 1.2f, 9.7f }; 995 | float[] a2 = javauto.arraySort(a1); 996 | 997 | assertThat(a2).hasSize(3).contains(1.2f, atIndex(0)) 998 | .contains(3.2f, atIndex(1)).contains(9.7f, atIndex(2)); 999 | } 1000 | 1001 | @Test 1002 | public void testArraySortInt() { 1003 | Javauto javauto = new Javauto(); 1004 | int[] a1 = { 2, 1, 9 }; 1005 | int[] a2 = javauto.arraySort(a1); 1006 | 1007 | assertThat(a2).hasSize(3).contains(1, atIndex(0)) 1008 | .contains(2, atIndex(1)).contains(9, atIndex(2)); 1009 | } 1010 | 1011 | @Test 1012 | public void testArraySortLong() { 1013 | Javauto javauto = new Javauto(); 1014 | long[] a1 = { 22, 10, 91 }; 1015 | long[] a2 = javauto.arraySort(a1); 1016 | 1017 | assertThat(a2).hasSize(3).contains(10, atIndex(0)) 1018 | .contains(22, atIndex(1)).contains(91, atIndex(2)); 1019 | } 1020 | 1021 | @Test 1022 | public void testArraySortShort() { 1023 | Javauto javauto = new Javauto(); 1024 | short[] a1 = { 22, 10, 91 }; 1025 | short[] a2 = javauto.arraySort(a1); 1026 | 1027 | assertThat(a2).hasSize(3).contains((short) 10, atIndex(0)) 1028 | .contains((short) 22, atIndex(1)) 1029 | .contains((short) 91, atIndex(2)); 1030 | } 1031 | 1032 | @Test 1033 | public void testArrayToStringBoolean() { 1034 | Javauto javauto = new Javauto(); 1035 | boolean[] a1 = new boolean[] { true, false }; 1036 | 1037 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase( 1038 | "[true, false]"); 1039 | } 1040 | 1041 | @Test 1042 | public void testArrayToStringByte() { 1043 | Javauto javauto = new Javauto(); 1044 | byte[] a1 = new byte[] { 5, 62 }; 1045 | 1046 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase("[5, 62]"); 1047 | } 1048 | 1049 | @Test 1050 | public void testArrayToStringChar() { 1051 | Javauto javauto = new Javauto(); 1052 | char[] a1 = new char[] { 'p', 's' }; 1053 | 1054 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase("[p, s]"); 1055 | } 1056 | 1057 | @Test 1058 | public void testArrayToStringDouble() { 1059 | Javauto javauto = new Javauto(); 1060 | double a1[] = { 5.4, 49.2 }; 1061 | 1062 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase( 1063 | "[5.4, 49.2]"); 1064 | } 1065 | 1066 | @Test 1067 | public void testArrayToStringFloat() { 1068 | Javauto javauto = new Javauto(); 1069 | float a1[] = { 5.2f, 46.1f }; 1070 | 1071 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase( 1072 | "[5.2, 46.1]"); 1073 | } 1074 | 1075 | @Test 1076 | public void testArrayToStringInt() { 1077 | Javauto javauto = new Javauto(); 1078 | int a1[] = { 5, 4 }; 1079 | 1080 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase("[5, 4]"); 1081 | } 1082 | 1083 | @Test 1084 | public void testArrayToStringLong() { 1085 | Javauto javauto = new Javauto(); 1086 | long a1[] = { 56, 46464 }; 1087 | 1088 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase( 1089 | "[56, 46464]"); 1090 | } 1091 | 1092 | @Test 1093 | public void testArrayToStringShort() { 1094 | Javauto javauto = new Javauto(); 1095 | short a1[] = { 5, 2 }; 1096 | 1097 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase("[5, 2]"); 1098 | } 1099 | 1100 | @Test 1101 | public void testArrayToStringString() { 1102 | Javauto javauto = new Javauto(); 1103 | String[] a1 = { "Julio", "Rey", "Pastor" }; 1104 | 1105 | assertThat(javauto.arrayToString(a1)).isEqualToIgnoringCase( 1106 | "[Julio, Rey, Pastor]"); 1107 | } 1108 | 1109 | @Test 1110 | public void testArrayEqualsBoolean() { 1111 | Javauto javauto = new Javauto(); 1112 | boolean[] a1 = new boolean[] { true, false }; 1113 | boolean[] a2 = new boolean[] { true, false }; 1114 | boolean[] a3 = new boolean[] { true, true }; 1115 | 1116 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1117 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1118 | } 1119 | 1120 | @Test 1121 | public void testArrayEqualsByte() { 1122 | Javauto javauto = new Javauto(); 1123 | byte[] a1 = new byte[] { 5, 62 }; 1124 | byte[] a2 = new byte[] { 5, 62 }; 1125 | byte[] a3 = new byte[] { 5 }; 1126 | 1127 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1128 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1129 | } 1130 | 1131 | @Test 1132 | public void testArrayEqualsChar() { 1133 | Javauto javauto = new Javauto(); 1134 | char[] a1 = new char[] { 'p', 's' }; 1135 | char[] a2 = new char[] { 'p', 's' }; 1136 | char[] a3 = new char[] { 'p', 'p' }; 1137 | 1138 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1139 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1140 | } 1141 | 1142 | @Test 1143 | public void testArrayEqualsDouble() { 1144 | Javauto javauto = new Javauto(); 1145 | double[] a1 = { 5.4, 49.2 }; 1146 | double[] a2 = { 5.4, 49.2 }; 1147 | double[] a3 = { 5.4, 2.1 }; 1148 | 1149 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1150 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1151 | } 1152 | 1153 | @Test 1154 | public void testArrayEqualsFloat() { 1155 | Javauto javauto = new Javauto(); 1156 | float[] a1 = { 5.2f, 46.1f }; 1157 | float[] a2 = { 5.2f, 46.1f }; 1158 | float[] a3 = { 5.2f, 6.1f }; 1159 | 1160 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1161 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1162 | } 1163 | 1164 | @Test 1165 | public void testArrayEqualsInt() { 1166 | Javauto javauto = new Javauto(); 1167 | int[] a1 = { 1, 2 }; 1168 | int[] a2 = { 1, 2 }; 1169 | int[] a3 = { 0, 2 }; 1170 | 1171 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1172 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1173 | } 1174 | 1175 | @Test 1176 | public void testArrayEqualsLong() { 1177 | Javauto javauto = new Javauto(); 1178 | long[] a1 = { 56, 46464 }; 1179 | long[] a2 = { 56, 46464 }; 1180 | long[] a3 = { 56, 46 }; 1181 | 1182 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1183 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1184 | } 1185 | 1186 | @Test 1187 | public void testArrayEqualsShort() { 1188 | Javauto javauto = new Javauto(); 1189 | short[] a1 = { 5, 2 }; 1190 | short[] a2 = { 5, 2 }; 1191 | short[] a3 = { 5, 5 }; 1192 | 1193 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1194 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1195 | } 1196 | 1197 | @Test 1198 | public void testArrayEqualsString() { 1199 | Javauto javauto = new Javauto(); 1200 | String[] a1 = { "Pierre", "Fermat" }; 1201 | String[] a2 = { "Pierre", "Fermat" }; 1202 | String[] a3 = { "Evariste", "Galois" }; 1203 | 1204 | assertThat(javauto.arrayEquals(a1, a2)).isTrue(); 1205 | assertThat(javauto.arrayEquals(a1, a3)).isFalse(); 1206 | } 1207 | 1208 | @Test 1209 | public void testGetEnvWithParameter() { 1210 | Javauto javauto = new Javauto(); 1211 | assertThat(javauto.getEnv("PATH")).isNotEmpty(); 1212 | } 1213 | 1214 | @Test 1215 | public void testGetEnvWithEmptyParameterShouldBeReturnAnEmptyString() { 1216 | Javauto javauto = new Javauto(); 1217 | assertThat(javauto.getEnv("")).isEmpty(); 1218 | } 1219 | 1220 | @Test 1221 | public void testGetEnvWithoutParameter() { 1222 | Javauto javauto = new Javauto(); 1223 | assertThat(javauto.getEnv()).isNotEmpty(); 1224 | } 1225 | 1226 | @Test 1227 | public void testArrayToClipString() { 1228 | Javauto javauto = new Javauto(); 1229 | String[] a1 = { "Pierre", "Fermat" }; 1230 | javauto.arrayToClip(a1); 1231 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase( 1232 | "[Pierre, Fermat]"); 1233 | } 1234 | 1235 | @Test 1236 | public void testArrayToClipByte() { 1237 | Javauto javauto = new Javauto(); 1238 | byte[] a1 = new byte[] { 5, 62 }; 1239 | javauto.arrayToClip(a1); 1240 | 1241 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[5, 62]"); 1242 | } 1243 | 1244 | @Test 1245 | public void testArrayToClipBoolean() { 1246 | Javauto javauto = new Javauto(); 1247 | boolean[] a1 = new boolean[] { true, false }; 1248 | javauto.arrayToClip(a1); 1249 | 1250 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase( 1251 | "[true, false]"); 1252 | } 1253 | 1254 | @Test 1255 | public void testArrayToClipChart() { 1256 | Javauto javauto = new Javauto(); 1257 | char[] a1 = new char[] { 'p', 's' }; 1258 | javauto.arrayToClip(a1); 1259 | 1260 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[p, s]"); 1261 | } 1262 | 1263 | @Test 1264 | public void testArrayToClipFloat() { 1265 | Javauto javauto = new Javauto(); 1266 | float[] a1 = { 5.2f, 46.1f }; 1267 | javauto.arrayToClip(a1); 1268 | 1269 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[5.2, 46.1]"); 1270 | } 1271 | 1272 | @Test 1273 | public void testArrayToClipInt() { 1274 | Javauto javauto = new Javauto(); 1275 | int[] a1 = { 5, 4 }; 1276 | javauto.arrayToClip(a1); 1277 | 1278 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[5, 4]"); 1279 | } 1280 | 1281 | @Test 1282 | public void testArrayToClipLong() { 1283 | Javauto javauto = new Javauto(); 1284 | long[] a1 = { 56, 46464 }; 1285 | javauto.arrayToClip(a1); 1286 | 1287 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[56, 46464]"); 1288 | } 1289 | 1290 | @Test 1291 | public void testArrayToClipShort() { 1292 | Javauto javauto = new Javauto(); 1293 | short[] a1 = { 5, 2 }; 1294 | javauto.arrayToClip(a1); 1295 | 1296 | assertThat(javauto.clipboardGet()).isEqualToIgnoringCase("[5, 2]"); 1297 | } 1298 | 1299 | } 1300 | -------------------------------------------------------------------------------- /src/test/java/com/automation/javauto/test/TestPanel.java: -------------------------------------------------------------------------------- 1 | package com.automation.javauto.test; 2 | 3 | import java.awt.event.InputEvent; 4 | import java.awt.event.MouseAdapter; 5 | import java.awt.event.MouseEvent; 6 | 7 | import javax.swing.JFrame; 8 | import javax.swing.JTextArea; 9 | 10 | /** 11 | * Creates a simple panel for testing purposes. 12 | * 13 | * @author henry.tejera 14 | * 15 | */ 16 | public class TestPanel extends JFrame { 17 | 18 | private static final long serialVersionUID = 1L; 19 | private String clickedButton; 20 | private int clickCount; 21 | 22 | /** 23 | * Create a new TestPanel instance. 24 | * 25 | * @param width 26 | * - The Width of the panel. 27 | * @param height 28 | * - The Height of the panel. 29 | * @param x 30 | * - x location. 31 | * @param y 32 | * - y location. 33 | */ 34 | public TestPanel(int width, int height, int x, int y) { 35 | setSize(width, height); 36 | setLocation(x, y); 37 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 38 | 39 | final JTextArea textArea = new JTextArea(); 40 | 41 | textArea.addMouseListener(new MouseAdapter() { 42 | public void mouseClicked(MouseEvent e) { 43 | if (e.getButton() == MouseEvent.NOBUTTON) { 44 | textArea.setText("No button clicked..."); 45 | setClickedButton("NoButton"); 46 | } else if (e.getButton() == MouseEvent.BUTTON1) { 47 | textArea.setText("Button left clicked..."); 48 | setClickedButton("left"); 49 | } else if (e.getButton() == MouseEvent.BUTTON2) { 50 | textArea.setText("Button left middle..."); 51 | setClickedButton("middle"); 52 | } else if (e.getButton() == MouseEvent.BUTTON3) { 53 | textArea.setText("Button left right..."); 54 | setClickedButton("right"); 55 | } 56 | setClickCount(getClickCount()); 57 | } 58 | }); 59 | 60 | getContentPane().add(textArea); 61 | setVisible(true); 62 | } 63 | 64 | /** 65 | * @return the clickedButton 66 | */ 67 | public String getClickedButton() { 68 | return clickedButton; 69 | } 70 | 71 | /** 72 | * @param clickedButton 73 | * the clickedButton to set 74 | */ 75 | public void setClickedButton(String clickedButton) { 76 | this.clickedButton = clickedButton; 77 | } 78 | 79 | /** 80 | * @return the clickCount 81 | */ 82 | public int getClickCount() { 83 | return clickCount; 84 | } 85 | 86 | /** 87 | * @param clickCount 88 | * the clickCount to set 89 | */ 90 | public void setClickCount(int clickCount) { 91 | this.clickCount = clickCount; 92 | } 93 | } -------------------------------------------------------------------------------- /src/test/resources/fermat.txt: -------------------------------------------------------------------------------- 1 | France Toulouse -------------------------------------------------------------------------------- /src/test/resources/script/tests.javauto: -------------------------------------------------------------------------------- 1 | global boolean ok; 2 | global int errCount; 3 | ok = true; 4 | errCount = 0; 5 | 6 | //#START PSEUDO-ASSERTS 7 | 8 | //Print an error and exit. 9 | //@param method - The method name in which the error occurred. 10 | //@para desscription - The error description. 11 | func void setError(String method, String description){ 12 | print("Error on [%s]. Description [%s]." % (method, description)); 13 | ok = false; 14 | errCount = errCount + 1; 15 | } 16 | 17 | //Assert that the given condition is true 18 | //@param condition 19 | //@param method - Method name. 20 | //@param message - Custom error message. 21 | func void assertThatIsTrue(boolean condition, String method, String message){ 22 | String msg = "Expected [true] but was [%s]" %(toString(condition)); 23 | 24 | if(!condition){ 25 | if(!message.isEmpty()){ 26 | msg = message; 27 | } 28 | setError(method, msg); 29 | } 30 | } 31 | 32 | //Assert that the given condition is false 33 | //@param condition 34 | //@param method - Method name. 35 | //@param message - Custom error message. 36 | func void assertThatIsFalse(boolean condition, String method, String message){ 37 | String msg = "Expected [false] but was [%s]" %(toString(condition)); 38 | 39 | if(condition){ 40 | if(!message.isEmpty()){ 41 | msg = message; 42 | } 43 | setError(method, msg); 44 | } 45 | } 46 | 47 | //Assert that two int values numerically are equals. 48 | //@param a - The first int. 49 | //@para b - The second int. 50 | //@param method - Method name. 51 | //@param message - Custom error message. 52 | func void assertThatIntEquals(int a, int b, String method, String message){ 53 | String msg = "Expected [%s] but was [%s]" %(toString(b), toString(a)); 54 | 55 | if(Integer.compare(a, b) != 0){ 56 | if(!message.isEmpty()){ 57 | msg = message; 58 | } 59 | setError(method, msg); 60 | } 61 | } 62 | 63 | //Assert that two strings lexicographically (ignoring case differences) are equals.s. 64 | //@param a - The first String. 65 | //@para b - The second String. 66 | //@param method - Method name. 67 | //@param message - Custom error message. 68 | func void assertThatStringEquals(String a, String b, String method, String message){ 69 | String msg = "Expected [%s] but was [%s]" %(b, a); 70 | 71 | if(!a.equals(b)){ 72 | if(!message.isEmpty()){ 73 | msg = message; 74 | } 75 | setError(method, msg); 76 | } 77 | } 78 | 79 | 80 | //#END PSEUDO-ASSERTS 81 | 82 | //#START TESTS 83 | func void testArrayAsListFunc(){ 84 | String method = "arrayAsList"; 85 | String[] a1 = {"a","b","c"}; 86 | List theList = arrayAsList(a1); 87 | assertThatIsTrue((theList.size() == 3), method,""); 88 | }; 89 | 90 | func void testArrayBinarySearchByte() { 91 | String method = "arrayBinarySearch (Byte)"; 92 | byte searchVal = 35; 93 | byte[] arr = { 10, 12, 34, searchVal, 5 }; 94 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 4, method, ""); 95 | } 96 | 97 | func void testArrayBinarySearchChart() { 98 | String method = "arrayBinarySearch (Chart)"; 99 | char searchVal = 'c'; 100 | char[] arr = {'a', 'c', 'b', 'e','d'}; 101 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 2, method, ""); 102 | } 103 | 104 | func void testArrayBinarySearchDouble() { 105 | String method = "arrayBinarySearch (Double)"; 106 | double searchVal = 4.6; 107 | double[] arr = {5.4,49.2,9.2,35.4,4.6}; 108 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 0, method, ""); 109 | } 110 | 111 | func void testArrayBinarySearchFloat() { 112 | String method = "arrayBinarySearch (Float)"; 113 | float searchVal = 42.9f; 114 | float[] arr = {5.2f,46.1f,42.9f,22.3f}; 115 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 2, method, ""); 116 | } 117 | 118 | func void testArrayBinarySearchInt() { 119 | String method = "arrayBinarySearch (Int)"; 120 | int searchVal = 5; 121 | int[] arr = {30,20,5,12,55}; 122 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 0, method, ""); 123 | } 124 | 125 | func void testArrayBinarySearchLong() { 126 | String method = "arrayBinarySearch (Long)"; 127 | long searchVal = 46464; 128 | long[] arr = {56,46464,3342,232,3445}; 129 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 4, method, ""); 130 | } 131 | 132 | func void testArrayBinarySearchShort() { 133 | String method = "arrayBinarySearch (Short)"; 134 | short searchVal = 52; 135 | short[] arr = {5,2,15,52,10}; 136 | assertThatIntEquals(arrayBinarySearch(arr, searchVal), 4, method, ""); 137 | } 138 | 139 | func void testArrayCopyOfBoolean() { 140 | String method = "arrayCopyOf (Boolean)"; 141 | boolean[] a1 = new boolean[] {true, false}; 142 | boolean[] a2 = arrayCopyOf(a1, 4); 143 | assertThatIntEquals(a2.length, 4, method, ""); 144 | } 145 | 146 | func void testArrayCopyOfBytes() { 147 | String method = "arrayCopyOf (Bytes)"; 148 | byte[] a1 = new byte[] { 5, 62, 15 }; 149 | byte[] a2 = arrayCopyOf(a1, 4); 150 | assertThatIntEquals(a2.length, 4, method, ""); 151 | } 152 | 153 | func void testArrayCopyOfChar() { 154 | String method = "arrayCopyOf (Char)"; 155 | char[] a1 = new char[] { 'p', 's', 'r' }; 156 | char[] a2 = arrayCopyOf(a1, 4); 157 | assertThatIntEquals(a2.length, 4, method, ""); 158 | } 159 | 160 | func void testArrayToStringBoolean() { 161 | String method = "arrayToString (Boolean)"; 162 | boolean[] a1 = new boolean[] { true, false }; 163 | assertThatStringEquals(arrayToString(a1),"[true, false]", method, ""); 164 | } 165 | 166 | func void testArrayToStringByte() { 167 | String method = "arrayToString (Byte)"; 168 | byte[] a1 = new byte[] { 5, 62 }; 169 | assertThatStringEquals(arrayToString(a1),"[5, 62]", method, ""); 170 | } 171 | 172 | func void testArrayToStringChar() { 173 | String method = "arrayToString (Char)"; 174 | char[] a1 = new char[] { 'p', 's' }; 175 | assertThatStringEquals(arrayToString(a1),"[p, s]", method, ""); 176 | } 177 | 178 | func void testArrayToStringDouble() { 179 | String method = "arrayToString (Double)"; 180 | double a1[] = { 5.4, 49.2 }; 181 | assertThatStringEquals(arrayToString(a1),"[5.4, 49.2]", method, ""); 182 | } 183 | 184 | func void testArrayToStringFloat() { 185 | String method = "arrayToString (Double)"; 186 | float a1[] = { 5.2f, 46.1f }; 187 | assertThatStringEquals(arrayToString(a1),"[5.2, 46.1]", method, ""); 188 | } 189 | 190 | func void testArrayToStringInt() { 191 | String method = "arrayToString (Int)"; 192 | int a1[] = { 5, 4 }; 193 | assertThatStringEquals(arrayToString(a1),"[5, 4]", method, ""); 194 | } 195 | 196 | func void testArrayToStringLong() { 197 | String method = "arrayToString (Long)"; 198 | long a1[] = { 56, 46464 }; 199 | assertThatStringEquals(arrayToString(a1),"[56, 46464]", method, ""); 200 | } 201 | 202 | func void testArrayToStringShort() { 203 | String method = "arrayToString (Short)"; 204 | short a1[] = { 5, 2 }; 205 | assertThatStringEquals(arrayToString(a1),"[5, 2]", method, ""); 206 | } 207 | 208 | func void testArrayToStringString() { 209 | String method = "arrayToString (String)"; 210 | String[] a1 = { "Julio", "Rey", "Pastor" }; 211 | String result = arrayToString(a1); 212 | assertThatStringEquals(arrayToString(a1),"[Julio, Rey, Pastor]", method, ""); 213 | } 214 | 215 | func void testArrayEqualsBoolean() { 216 | String method = "arrayEquals (Boolean)"; 217 | boolean[] a1 = new boolean[] { true, false }; 218 | boolean[] a2 = new boolean[] { true, false }; 219 | boolean[] a3 = new boolean[] { true, true }; 220 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 221 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 222 | } 223 | 224 | func void testArrayEqualsByte() { 225 | String method = "arrayEquals (Byte)"; 226 | byte[] a1 = new byte[] { 5, 62 }; 227 | byte[] a2 = new byte[] { 5, 62 }; 228 | byte[] a3 = new byte[] { 5 }; 229 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 230 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 231 | } 232 | 233 | func void testArrayEqualsChar() { 234 | String method = "arrayEquals (Char)"; 235 | char[] a1 = new char[] { 'p', 's' }; 236 | char[] a2 = new char[] { 'p', 's' }; 237 | char[] a3 = new char[] { 'p', 'p' }; 238 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 239 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 240 | } 241 | 242 | func void testArrayEqualsDouble() { 243 | String method = "arrayEquals (Double)"; 244 | double[] a1 = { 5.4, 49.2 }; 245 | double[] a2 = { 5.4, 49.2 }; 246 | double[] a3 = { 5.4, 2.1 }; 247 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 248 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 249 | } 250 | 251 | func void testArrayEqualsFloat() { 252 | String method = "arrayEquals (Float)"; 253 | float[] a1 = { 5.2f, 46.1f }; 254 | float[] a2 = { 5.2f, 46.1f }; 255 | float[] a3 = { 5.2f, 6.1f }; 256 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 257 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 258 | } 259 | 260 | func void testArrayEqualsInt() { 261 | String method = "arrayEquals (Int)"; 262 | int[] a1 = { 1, 2 }; 263 | int[] a2 = { 1, 2 }; 264 | int[] a3 = { 0, 2 }; 265 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 266 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 267 | } 268 | 269 | func void testArrayEqualsLong() { 270 | String method = "arrayEquals (Long)"; 271 | long[] a1 = { 56, 46464 }; 272 | long[] a2 = { 56, 46464 }; 273 | long[] a3 = { 56, 46 }; 274 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 275 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 276 | } 277 | 278 | func void testArrayEqualsShort() { 279 | String method = "arrayEquals (Short)"; 280 | short[] a1 = { 5, 2 }; 281 | short[] a2 = { 5, 2 }; 282 | short[] a3 = { 5, 5 }; 283 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 284 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 285 | } 286 | 287 | func void testArrayEqualsString() { 288 | String method = "arrayEquals (String)"; 289 | String[] a1 = { "Pierre", "Fermat" }; 290 | String[] a2 = { "Pierre", "Fermat" }; 291 | String[] a3 = { "Evariste", "Galois" }; 292 | assertThatIsTrue((arrayEquals(a1, a2)), method, ""); 293 | assertThatIsFalse((arrayEquals(a1, a3)), method, ""); 294 | } 295 | 296 | func void testClipboardPutAndGet(){ 297 | String method = "clipboardPut & clipboardGet"; 298 | String clip = "put me in the clipboard!"; 299 | clipboardPut(clip); 300 | assertThatStringEquals(clip,clipboardGet(), method, ""); 301 | } 302 | 303 | func void testSetAndGetSpeed(){ 304 | String method = "setSpeed & getSpeed"; 305 | double spd = 0.5; 306 | setSpeed(spd); 307 | assertThatStringEquals(toString(spd), toString(getSpeed()), method, ""); 308 | } 309 | 310 | func void testGetEnvWithParameter(){ 311 | String method = "envGet (String)"; 312 | String value = getEnv("PATH"); 313 | assertThatIsFalse(value.isEmpty(), method, ""); 314 | } 315 | 316 | func void testGetEnvWithEmptyParameter(){ 317 | String method = "envGet"; 318 | String value = getEnv(""); 319 | assertThatIsTrue(value.isEmpty(), method, ""); 320 | } 321 | 322 | func void testGetEnvWithoutParameter(){ 323 | String method = "envGet"; 324 | String value = getEnv(); 325 | assertThatIsFalse(value.isEmpty(), method, ""); 326 | } 327 | 328 | func void testArrayToClipString() { 329 | String method = "arrayToClip (String)"; 330 | String[] a1 = { "Pierre", "Fermat" }; 331 | arrayToClip(a1); 332 | assertThatStringEquals(clipboardGet(), "[Pierre, Fermat]", method, ""); 333 | } 334 | 335 | func void testArrayToClipByte() { 336 | String method = "arrayToClip (Byte)"; 337 | byte[] a1 = new byte[] { 5, 62 }; 338 | arrayToClip(a1); 339 | assertThatStringEquals(clipboardGet(), "[5, 62]", method, ""); 340 | } 341 | 342 | func void testArrayToClipBoolean() { 343 | String method = "arrayToClip (Boolean)"; 344 | boolean[] a1 = new boolean[] { true, false }; 345 | arrayToClip(a1); 346 | assertThatStringEquals(clipboardGet(), "[true, false]", method, ""); 347 | } 348 | 349 | func void testArrayToClipChart() { 350 | String method = "arrayToClip (Chart)"; 351 | char[] a1 = new char[] { 'p', 's' }; 352 | arrayToClip(a1); 353 | assertThatStringEquals(clipboardGet(), "[p, s]", method, ""); 354 | } 355 | 356 | func void testArrayToClipFloat() { 357 | String method = "arrayToClip (Float)"; 358 | float[] a1 = { 5.2f, 46.1f }; 359 | arrayToClip(a1); 360 | assertThatStringEquals(clipboardGet(), "[5.2, 46.1]", method, ""); 361 | } 362 | 363 | func void testArrayToClipInt() { 364 | String method = "arrayToClip (Int)"; 365 | int[] a1 = { 5, 4 }; 366 | arrayToClip(a1); 367 | assertThatStringEquals(clipboardGet(), "[5, 4]", method, ""); 368 | } 369 | 370 | func void testArrayToClipLong() { 371 | String method = "arrayToClip (Long)"; 372 | long[] a1 = { 56, 46464 }; 373 | arrayToClip(a1); 374 | assertThatStringEquals(clipboardGet(), "[56, 46464]", method, ""); 375 | } 376 | 377 | func void testArrayToClipShort() { 378 | String method = "arrayToClip (Short)"; 379 | short[] a1 = { 5, 2 }; 380 | arrayToClip(a1); 381 | assertThatStringEquals(clipboardGet(), "[5, 2]", method, ""); 382 | } 383 | //#END TESTS 384 | 385 | 386 | //Test suite. 387 | func void suite(){ 388 | testArrayAsListFunc(); 389 | testArrayBinarySearchByte(); 390 | testArrayBinarySearchChart(); 391 | testArrayBinarySearchDouble(); 392 | testArrayBinarySearchFloat(); 393 | testArrayBinarySearchInt(); 394 | testArrayBinarySearchLong(); 395 | testArrayBinarySearchShort(); 396 | testArrayCopyOfBoolean(); 397 | testArrayCopyOfBytes(); 398 | testArrayToStringBoolean(); 399 | testArrayToStringChar(); 400 | testArrayToStringDouble(); 401 | testArrayToStringFloat(); 402 | testArrayToStringInt(); 403 | testArrayToStringLong(); 404 | testArrayToStringShort(); 405 | testArrayToStringString(); 406 | testArrayEqualsBoolean(); 407 | testArrayEqualsByte(); 408 | testArrayEqualsChar(); 409 | testArrayEqualsDouble(); 410 | testArrayEqualsFloat(); 411 | testArrayEqualsInt(); 412 | testArrayEqualsLong(); 413 | testArrayEqualsShort(); 414 | testArrayEqualsString(); 415 | testClipboardPutAndGet(); 416 | testSetAndGetSpeed(); 417 | testGetEnvWithParameter(); 418 | testGetEnvWithEmptyParameter(); 419 | testGetEnvWithoutParameter(); 420 | testArrayToClipString(); 421 | testArrayToClipByte(); 422 | testArrayToClipBoolean(); 423 | testArrayToClipChart(); 424 | testArrayToClipFloat(); 425 | testArrayToClipInt(); 426 | testArrayToClipLong(); 427 | testArrayToClipShort(); 428 | } 429 | 430 | suite(); 431 | 432 | if(ok){ 433 | print("Far out! Everything passed!"); 434 | exit(); 435 | } else { 436 | print("Bummer! You have failing tests!. Errors count [%s]" % (toString(errCount))); 437 | exit(1); 438 | } 439 | --------------------------------------------------------------------------------