diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index fe7a72f..839e71b 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,32 +1,35 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven +name: Java Maven Tests -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - - -name: Java CI with Maven - -on: [push, pull_request] +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] jobs: build: - permissions: write-all runs-on: ubuntu-latest + strategy: + matrix: + java-version: ['11', '17'] + steps: - uses: actions/checkout@v3 - - name: Set up JDK 17 + + - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v3 with: - java-version: '17' - distribution: 'zulu' + java-version: ${{ matrix.java-version }} + distribution: 'temurin' cache: maven - name: Build with Maven - run: mvn -B package --file pom.xml + run: mvn -B compile --file pom.xml + + - name: Run tests with Maven + run: mvn -B test --file pom.xml - - name: Run the Maven verify phase - run: mvn --batch-mode --update-snapshots verify + - name: Generate test report + if: always() + run: mvn -B surefire-report:report --file pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4421762 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +target/ +.classpath +.project +.settings/ +*.class +*.jar +*.log +.DS_Store +.vscode/ +.idea/ +*.iml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..45c131b --- /dev/null +++ b/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + com.mycompany.app + my-app + 1.0-SNAPSHOT + + my-app + Maven Project with Square Root Calculator Tests + + + UTF-8 + 11 + 11 + + + + + junit + junit + 4.13.2 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + 11 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + diff --git a/src/main/java/com/mycompany/app/App.java b/src/main/java/com/mycompany/app/App.java new file mode 100644 index 0000000..1dab526 --- /dev/null +++ b/src/main/java/com/mycompany/app/App.java @@ -0,0 +1,10 @@ +package com.mycompany.app; + +public class App { + public static void main(String[] args) { + double val = Double.parseDouble("2.0"); + Sqrt sqrt = new Sqrt(val); + double result = sqrt.calc(); + System.out.println("Sqrt of " + val + " = " + result); + } +} diff --git a/src/main/java/com/mycompany/app/Sqrt.java b/src/main/java/com/mycompany/app/Sqrt.java new file mode 100644 index 0000000..db99b11 --- /dev/null +++ b/src/main/java/com/mycompany/app/Sqrt.java @@ -0,0 +1,56 @@ +package com.mycompany.app; + +public class Sqrt { + private static final double DEFAULT_DELTA = 0.00000001; + private double delta; + private double arg; + + public Sqrt(double arg) { + this(arg, DEFAULT_DELTA); + } + + public Sqrt(double arg, double delta) { + this.arg = arg; + this.delta = delta; + } + + public double average(double x, double y) { + return (x + y) / 2.0; + } + + public boolean good(double guess, double x) { + return Math.abs(guess * guess - x) < delta; + } + + public double improve(double guess, double x) { + return average(guess, x / guess); + } + + public double iter(double guess, double x) { + while (!good(guess, x)) { + guess = improve(guess, x); + } + return guess; + } + + public double calc() { + if (arg < 0) + throw new IllegalArgumentException("Argument must be non-negative: " + arg); + if (arg == 0.0) + return 0.0; + double initialGuess = (arg >= 1.0) ? arg / 2.0 : 1.0; + return iter(initialGuess, arg); + } + + public double getArg() { + return arg; + } + + public double getDelta() { + return delta; + } + + public void setDelta(double delta) { + this.delta = delta; + } +} diff --git a/src/test/java/com/mycompany/app/AppTest.java b/src/test/java/com/mycompany/app/AppTest.java new file mode 100644 index 0000000..16377d6 --- /dev/null +++ b/src/test/java/com/mycompany/app/AppTest.java @@ -0,0 +1,211 @@ +package com.mycompany.app; + +import org.junit.Test; +import org.junit.Before; +import static org.junit.Assert.*; + +public class AppTest { + private Sqrt sqrt; + private static final double EPSILON = 1e-6; + + @Before + public void setUp() { + sqrt = new Sqrt(2.0); + } + + @Test + public void testConstructorDefaultDelta() { + Sqrt s = new Sqrt(4.0); + assertEquals(4.0, s.getArg(), EPSILON); + assertEquals(0.00000001, s.getDelta(), EPSILON); + } + + @Test + public void testConstructorCustomDelta() { + Sqrt s = new Sqrt(9.0, 0.0001); + assertEquals(9.0, s.getArg(), EPSILON); + assertEquals(0.0001, s.getDelta(), EPSILON); + } + + @Test + public void testAveragePositive() { + double result = sqrt.average(4.0, 6.0); + assertEquals(5.0, result, EPSILON); + } + + @Test + public void testAverageNegative() { + double result = sqrt.average(-2.0, -4.0); + assertEquals(-3.0, result, EPSILON); + } + + @Test + public void testAverageWithZero() { + double result = sqrt.average(0.0, 10.0); + assertEquals(5.0, result, EPSILON); + } + + @Test + public void testGoodReturnsTrueWhenCloseEnough() { + Sqrt s = new Sqrt(4.0); + boolean result = s.good(2.0, 4.0); + assertTrue(result); + } + + @Test + public void testGoodReturnsFalseWhenNotCloseEnough() { + Sqrt s = new Sqrt(4.0); + boolean result = s.good(1.5, 4.0); + assertFalse(result); + } + + @Test + public void testImprove() { + Sqrt s = new Sqrt(2.0); + double initialGuess = 1.5; + double improved = s.improve(initialGuess, 2.0); + assertEquals(1.416666666, improved, EPSILON); + } + + @Test + public void testIter() { + Sqrt s = new Sqrt(4.0); + double result = s.iter(1.0, 4.0); + assertEquals(2.0, result, EPSILON); + } + + @Test + public void testCalcPerfectSquare4() { + Sqrt s = new Sqrt(4.0); + double result = s.calc(); + assertEquals(2.0, result, EPSILON); + } + + @Test + public void testCalcPerfectSquare9() { + Sqrt s = new Sqrt(9.0); + double result = s.calc(); + assertEquals(3.0, result, EPSILON); + } + + @Test + public void testCalcNonPerfectSquare2() { + Sqrt s = new Sqrt(2.0); + double result = s.calc(); + assertEquals(Math.sqrt(2.0), result, EPSILON); + assertTrue(Math.abs(result - 1.414213562) < 0.0001); + } + + @Test + public void testCalcOne() { + Sqrt s = new Sqrt(1.0); + double result = s.calc(); + assertEquals(1.0, result, EPSILON); + } + + @Test + public void testCalcSmallDecimal() { + Sqrt s = new Sqrt(0.25); + double result = s.calc(); + assertEquals(0.5, result, EPSILON); + } + + @Test + public void testCalcLargeNumber() { + Sqrt s = new Sqrt(100.0); + double result = s.calc(); + assertEquals(10.0, result, EPSILON); + } + + @Test + public void testCalcVeryLargeNumber() { + Sqrt s = new Sqrt(10000.0); + double result = s.calc(); + assertEquals(100.0, result, EPSILON); + } + + @Test + public void testGetDelta() { + Sqrt s = new Sqrt(5.0, 0.001); + assertEquals(0.001, s.getDelta(), EPSILON); + } + + @Test + public void testSetDelta() { + Sqrt s = new Sqrt(5.0); + s.setDelta(0.01); + assertEquals(0.01, s.getDelta(), EPSILON); + } + + @Test + public void testGetArg() { + Sqrt s = new Sqrt(7.5); + assertEquals(7.5, s.getArg(), EPSILON); + } + + @Test + public void testHigherPrecision() { + Sqrt s = new Sqrt(2.0, 0.00000001); + double result = s.calc(); + double expectedSqrt2 = 1.41421356237; + assertEquals(expectedSqrt2, result, 0.00000001); + } + + @Test + public void testCalcFractional() { + Sqrt s = new Sqrt(3.0); + double result = s.calc(); + assertEquals(Math.sqrt(3.0), result, EPSILON); + assertTrue(Math.abs(result - 1.732050808) < 0.0001); + } + + @Test + public void testCalcGoldenRatio() { + double phi = (1.0 + Math.sqrt(5.0)) / 2.0; + Sqrt s = new Sqrt(phi * phi); + double result = s.calc(); + assertEquals(phi, result, EPSILON); + } + + @Test + public void testMultipleCalcsWithSameObject() { + Sqrt s1 = new Sqrt(4.0); + double result1 = s1.calc(); + assertEquals(2.0, result1, EPSILON); + + Sqrt s2 = new Sqrt(9.0); + double result2 = s2.calc(); + assertEquals(3.0, result2, EPSILON); + } + + @Test + public void testAverageSameNumbers() { + double result = sqrt.average(5.0, 5.0); + assertEquals(5.0, result, EPSILON); + } + + @Test + public void testGoodWithExactMatch() { + Sqrt s = new Sqrt(1.0, 0.00000001); + boolean result = s.good(1.0, 1.0); + assertTrue(result); + } + + @Test(expected = IllegalArgumentException.class) + public void testNegativeArgThrows() { + Sqrt s = new Sqrt(-4.0); + s.calc(); + } + + @Test + public void testUniqueRandomCases() { + long seed = System.currentTimeMillis() ^ System.getProperty("user.name").hashCode(); + java.util.Random rnd = new java.util.Random(seed); + for (int i = 0; i < 50; i++) { + double val = 1e-6 + rnd.nextDouble() * 1e6; // range [1e-6, 1e6+1e-6] + Sqrt s = new Sqrt(val, 1e-7); + double result = s.calc(); + assertEquals(Math.sqrt(val), result, 1e-6); + } + } +}