diff --git a/cli/code-to-optimize/build.gradle b/cli/code-to-optimize/build.gradle new file mode 100644 index 000000000..d9494272d --- /dev/null +++ b/cli/code-to-optimize/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'java' +} + +group = 'com.example' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + // JUnit 5 (Jupiter) + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.1' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.1' + + // JUnit 4 + testImplementation 'junit:junit:4.13.2' + + // JUnit Vintage to run JUnit 4 tests with JUnit 5 + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.10.1' +} + +test { + useJUnitPlatform() +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} diff --git a/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.jar b/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..d64cd4917 Binary files /dev/null and b/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.jar differ diff --git a/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.properties b/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..1af9e0930 --- /dev/null +++ b/cli/code-to-optimize/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/cli/code-to-optimize/gradlew b/cli/code-to-optimize/gradlew new file mode 100755 index 000000000..1461f75c1 --- /dev/null +++ b/cli/code-to-optimize/gradlew @@ -0,0 +1,189 @@ +#!/bin/sh + +############################################################################## +# Gradle start up script for UN*X +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/cli/code-to-optimize/settings.gradle b/cli/code-to-optimize/settings.gradle new file mode 100644 index 000000000..344b8de95 --- /dev/null +++ b/cli/code-to-optimize/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'code-optimization-demo' diff --git a/cli/code-to-optimize/src/main/java/com/example/optimization/CollectionProcessor.java b/cli/code-to-optimize/src/main/java/com/example/optimization/CollectionProcessor.java new file mode 100644 index 000000000..f2e5eb9fd --- /dev/null +++ b/cli/code-to-optimize/src/main/java/com/example/optimization/CollectionProcessor.java @@ -0,0 +1,66 @@ +package com.example.optimization; + +import java.util.ArrayList; +import java.util.List; + +/** + * Collection processing class with inefficient implementations + * that need optimization. + */ +public class CollectionProcessor { + + /** + * Inefficient: Uses contains() which is O(n) for ArrayList + * Should use HashSet for O(1) lookup + */ + public List removeDuplicates(List numbers) { + List result = new ArrayList<>(); + for (Integer num : numbers) { + if (!result.contains(num)) { + result.add(num); + } + } + return result; + } + + /** + * Inefficient: Multiple passes through the collection + * Should use a single pass with tracking variables + */ + public int sumOfEvens(List numbers) { + List evens = new ArrayList<>(); + for (Integer num : numbers) { + if (num % 2 == 0) { + evens.add(num); + } + } + + int sum = 0; + for (Integer num : evens) { + sum += num; + } + return sum; + } + + /** + * Inefficient: Creates new list on each recursive call + * Should use iterative approach or accumulator + */ + public List filterPositive(List numbers) { + if (numbers.isEmpty()) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + Integer first = numbers.get(0); + + if (first > 0) { + result.add(first); + } + + List rest = numbers.subList(1, numbers.size()); + result.addAll(filterPositive(rest)); + + return result; + } +} diff --git a/cli/code-to-optimize/src/main/java/com/example/optimization/DataCalculator.java b/cli/code-to-optimize/src/main/java/com/example/optimization/DataCalculator.java new file mode 100644 index 000000000..fde6eba3b --- /dev/null +++ b/cli/code-to-optimize/src/main/java/com/example/optimization/DataCalculator.java @@ -0,0 +1,47 @@ +package com.example.optimization; + +/** + * Data calculation class with inefficient implementations + * that need optimization. + */ +public class DataCalculator { + + /** + * Inefficient: Recalculates Fibonacci values recursively without memoization + * Should use dynamic programming or iterative approach + */ + public long fibonacci(int n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); + } + + /** + * Inefficient: Uses trial division for every number + * Should use Sieve of Eratosthenes for multiple primes + */ + public boolean isPrime(int number) { + if (number <= 1) { + return false; + } + for (int i = 2; i < number; i++) { + if (number % i == 0) { + return false; + } + } + return true; + } + + /** + * Inefficient: Uses pow and division operations unnecessarily + * Should use modular arithmetic directly + */ + public int powerModulo(int base, int exponent, int modulo) { + int result = 1; + for (int i = 0; i < exponent; i++) { + result = (result * base) % modulo; + } + return result; + } +} diff --git a/cli/code-to-optimize/src/main/java/com/example/optimization/StringProcessor.java b/cli/code-to-optimize/src/main/java/com/example/optimization/StringProcessor.java new file mode 100644 index 000000000..84a6ff675 --- /dev/null +++ b/cli/code-to-optimize/src/main/java/com/example/optimization/StringProcessor.java @@ -0,0 +1,52 @@ +package com.example.optimization; + +import java.util.List; + +/** + * String processing class with inefficient implementations + * that need optimization. + */ +public class StringProcessor { + + /** + * Inefficient: Uses String concatenation in a loop + * Should use StringBuilder for better performance + */ + public String concatenateStrings(List strings) { + String result = ""; + for (String str : strings) { + result += str + " "; + } + return result.trim(); + } + + /** + * Inefficient: Creates multiple intermediate String objects + * Should use StringBuilder or single replace chain + */ + public String sanitizeInput(String input) { + String result = input; + result = result.replace("&", "&"); + result = result.replace("<", "<"); + result = result.replace(">", ">"); + result = result.replace("\"", """); + result = result.replace("'", "'"); + return result; + } + + /** + * Inefficient: Uses repeated substring operations + * Should use a single pass algorithm + */ + public String reverseWords(String sentence) { + String[] words = sentence.split(" "); + String result = ""; + for (int i = words.length - 1; i >= 0; i--) { + result += words[i]; + if (i > 0) { + result += " "; + } + } + return result; + } +} diff --git a/cli/code-to-optimize/src/test/java/com/example/optimization/CollectionProcessorTest.java b/cli/code-to-optimize/src/test/java/com/example/optimization/CollectionProcessorTest.java new file mode 100644 index 000000000..f55ae9462 --- /dev/null +++ b/cli/code-to-optimize/src/test/java/com/example/optimization/CollectionProcessorTest.java @@ -0,0 +1,71 @@ +package com.example.optimization; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * JUnit 4 tests for CollectionProcessor + */ +public class CollectionProcessorTest { + + private CollectionProcessor processor; + + @Before + public void setUp() { + processor = new CollectionProcessor(); + } + + @Test + public void testRemoveDuplicates() { + List numbers = Arrays.asList(1, 2, 3, 2, 4, 3, 5); + List result = processor.removeDuplicates(numbers); + assertEquals(Arrays.asList(1, 2, 3, 4, 5), result); + } + + @Test + public void testRemoveDuplicatesEmptyList() { + List numbers = Arrays.asList(); + List result = processor.removeDuplicates(numbers); + assertTrue(result.isEmpty()); + } + + @Test + public void testSumOfEvens() { + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + int result = processor.sumOfEvens(numbers); + assertEquals(12, result); // 2 + 4 + 6 = 12 + } + + @Test + public void testSumOfEvensNoEvens() { + List numbers = Arrays.asList(1, 3, 5, 7); + int result = processor.sumOfEvens(numbers); + assertEquals(0, result); + } + + @Test + public void testFilterPositive() { + List numbers = Arrays.asList(-2, 3, -1, 5, 0, 7); + List result = processor.filterPositive(numbers); + assertEquals(Arrays.asList(3, 5, 7), result); + } + + @Test + public void testFilterPositiveAllNegative() { + List numbers = Arrays.asList(-1, -2, -3); + List result = processor.filterPositive(numbers); + assertTrue(result.isEmpty()); + } + + @Test + public void testFilterPositiveAllPositive() { + List numbers = Arrays.asList(1, 2, 3); + List result = processor.filterPositive(numbers); + assertEquals(Arrays.asList(1, 2, 3), result); + } +} diff --git a/cli/code-to-optimize/src/test/java/com/example/optimization/DataCalculatorTest.java b/cli/code-to-optimize/src/test/java/com/example/optimization/DataCalculatorTest.java new file mode 100644 index 000000000..508e3cddd --- /dev/null +++ b/cli/code-to-optimize/src/test/java/com/example/optimization/DataCalculatorTest.java @@ -0,0 +1,93 @@ +package com.example.optimization; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit 5 tests for DataCalculator + */ +@DisplayName("DataCalculator Tests (JUnit 5)") +class DataCalculatorTest { + + private DataCalculator calculator; + + @BeforeEach + void setUp() { + calculator = new DataCalculator(); + } + + @Test + @DisplayName("Should calculate Fibonacci for n=0") + void testFibonacciZero() { + assertEquals(0, calculator.fibonacci(0)); + } + + @Test + @DisplayName("Should calculate Fibonacci for n=1") + void testFibonacciOne() { + assertEquals(1, calculator.fibonacci(1)); + } + + @ParameterizedTest + @DisplayName("Should calculate Fibonacci correctly") + @CsvSource({ + "2, 1", + "3, 2", + "4, 3", + "5, 5", + "6, 8", + "7, 13", + "10, 55" + }) + void testFibonacci(int n, long expected) { + assertEquals(expected, calculator.fibonacci(n)); + } + + @ParameterizedTest + @DisplayName("Should identify prime numbers correctly") + @CsvSource({ + "2, true", + "3, true", + "4, false", + "5, true", + "17, true", + "20, false", + "23, true", + "100, false" + }) + void testIsPrime(int number, boolean expected) { + assertEquals(expected, calculator.isPrime(number)); + } + + @Test + @DisplayName("Should return false for negative numbers") + void testIsPrimeNegative() { + assertFalse(calculator.isPrime(-5)); + } + + @Test + @DisplayName("Should return false for 0 and 1") + void testIsPrimeZeroAndOne() { + assertFalse(calculator.isPrime(0)); + assertFalse(calculator.isPrime(1)); + } + + @Test + @DisplayName("Should calculate power modulo correctly") + void testPowerModulo() { + assertEquals(4, calculator.powerModulo(2, 2, 5)); // 2^2 % 5 = 4 + assertEquals(1, calculator.powerModulo(3, 4, 10)); // 3^4 % 10 = 81 % 10 = 1 + assertEquals(0, calculator.powerModulo(5, 3, 5)); // 5^3 % 5 = 0 + } + + @Test + @DisplayName("Should handle exponent 0") + void testPowerModuloZeroExponent() { + assertEquals(1, calculator.powerModulo(5, 0, 7)); // Any number^0 = 1 + } +} diff --git a/cli/code-to-optimize/src/test/java/com/example/optimization/StringProcessorTest.java b/cli/code-to-optimize/src/test/java/com/example/optimization/StringProcessorTest.java new file mode 100644 index 000000000..b93f5f1ed --- /dev/null +++ b/cli/code-to-optimize/src/test/java/com/example/optimization/StringProcessorTest.java @@ -0,0 +1,74 @@ +package com.example.optimization; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit 5 tests for StringProcessor + */ +@DisplayName("StringProcessor Tests (JUnit 5)") +class StringProcessorTest { + + private StringProcessor processor; + + @BeforeEach + void setUp() { + processor = new StringProcessor(); + } + + @Test + @DisplayName("Should concatenate strings correctly") + void testConcatenateStrings() { + List strings = Arrays.asList("Hello", "World", "Java"); + String result = processor.concatenateStrings(strings); + assertEquals("Hello World Java", result); + } + + @Test + @DisplayName("Should handle empty list") + void testConcatenateEmptyList() { + List strings = Arrays.asList(); + String result = processor.concatenateStrings(strings); + assertEquals("", result); + } + + @Test + @DisplayName("Should sanitize HTML special characters") + void testSanitizeInput() { + String input = ""; + String result = processor.sanitizeInput(input); + assertEquals("<script>alert('XSS')</script>", result); + } + + @Test + @DisplayName("Should handle input with quotes") + void testSanitizeQuotes() { + String input = "He said \"Hello\" & 'Goodbye'"; + String result = processor.sanitizeInput(input); + assertTrue(result.contains(""")); + assertTrue(result.contains("'")); + assertTrue(result.contains("&")); + } + + @Test + @DisplayName("Should reverse words in sentence") + void testReverseWords() { + String sentence = "Hello World Java"; + String result = processor.reverseWords(sentence); + assertEquals("Java World Hello", result); + } + + @Test + @DisplayName("Should handle single word") + void testReverseSingleWord() { + String sentence = "Hello"; + String result = processor.reverseWords(sentence); + assertEquals("Hello", result); + } +}