From e8475ecaee16582d7805b444267cfbbfff7664bc Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 18:29:59 +0100 Subject: [PATCH 1/7] Add JVM interop --- build.gradle.kts | 2 ++ src/testgen/testgen/Java.hs | 48 +++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4e3304a..2147b79 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -112,6 +112,7 @@ pitest { // Test generation tasks.register("generateQuickCheckTests") { + dependsOn(tasks.jar) workingDir = file("src/testgen") commandLine = listOf("cabal", "run") } @@ -144,6 +145,7 @@ tasks.named("run") { } tasks.register("repl") { + dependsOn(tasks.jar) workingDir = file("src/testgen") commandLine = listOf("cabal", "repl") standardInput = System.`in` diff --git a/src/testgen/testgen/Java.hs b/src/testgen/testgen/Java.hs index 9fbd4a9..d107c76 100644 --- a/src/testgen/testgen/Java.hs +++ b/src/testgen/testgen/Java.hs @@ -23,12 +23,27 @@ module Java , assertTrue , assertEquals , assertSame - , assertThrows) where + , assertThrows + , runJava + ) where import Data.Char (isAscii, ord) -import Data.List (intercalate) +import Data.List (intercalate, isPrefixOf) import Numeric (showHex) +import System.Process + ( + StdStream(CreatePipe) + , createProcess + , proc + , std_in + , std_out + , std_err + , waitForProcess + ) +import System.IO (Handle, hClose, hGetContents, hPutStr) +import Control.Exception (bracket, evaluate) + -- JavaData definition class JavaData a where -- | Gets the equivalent Java name for this Haskell type @@ -181,3 +196,32 @@ assertThrows e b = " }" , ");" ] + +-- JVM interop + +-- | Runs Java code with classes the project classes loaded +runJava :: [String] -- ^ Java statements + -> IO [String] -- ^ Lines output by the statements +runJava statements = do + (Just stdin, Just stdout, Just stderr, process) <- createProcess + (proc "jshell" ["--class-path=../../build/libs/ATS.jar"]) + { std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe } + + bracket + (return ()) + (\_ -> do + hClose stdin + hClose stdout + hClose stderr + ) + (\_ -> do + hPutStr stdin (unlines statements) + hClose stdin + + output <- hGetContents stdout + evaluate (length output) -- Force deep strict evaluation + let outputLines = lines output + + waitForProcess process + return $ filter (not . isPrefixOf "| ") outputLines + ) From 038973cd8c0a755e8bda8bc350768d33bcabf3d7 Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 18:49:40 +0100 Subject: [PATCH 2/7] Add example JVM test --- src/testgen/testgen/FacadeTemplates.hs | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/testgen/testgen/FacadeTemplates.hs b/src/testgen/testgen/FacadeTemplates.hs index f34954e..9fab41b 100644 --- a/src/testgen/testgen/FacadeTemplates.hs +++ b/src/testgen/testgen/FacadeTemplates.hs @@ -13,12 +13,13 @@ -- limitations under the License. module FacadeTemplates ( - equalityTemplate + equalityTemplate, + emailTemplate ) where -import Java (assertEquals, toJavaExpression) -import TestTemplate (TestTemplate, genToTestTemplate) -import Test.QuickCheck (Gen, arbitrary) +import Java (assertEquals, runJava, toJavaExpression) +import TestTemplate (TestTemplate(..), genToTestTemplate) +import Test.QuickCheck (Gen, arbitrary, elements, generate, listOf) equalityTestGenerator :: Gen [String] equalityTestGenerator = do @@ -32,3 +33,25 @@ equalityTestGenerator = do equalityTemplate :: TestTemplate equalityTemplate = genToTestTemplate "equals" equalityTestGenerator 3 + +genEmail :: Gen String +genEmail = do + before <- listOf $ elements (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']) + after <- listOf $ elements (['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']) + return $ before ++ "@" ++ after ++ ".com" + +emailTestGenerator :: IO [String] +emailTestGenerator = do + email <- generate $ genEmail + resultLines <- runJava + [ + "import MakeItFit.utils.EmailValidator;" + , "System.out.println(EmailValidator.isValidEmail(" ++ toJavaExpression email ++ "));" + ] + return + [ + assertEquals (toJavaExpression email) (last resultLines) + ] + +emailTemplate :: TestTemplate +emailTemplate = TestTemplate "validEmail" emailTestGenerator 1 From ff9bd27d648dadd71e6774d381e0df083372019c Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 19:06:32 +0100 Subject: [PATCH 3/7] Add test generator entry point --- src/testgen/testgen/Main.hs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/testgen/testgen/Main.hs b/src/testgen/testgen/Main.hs index cfd672e..bf6a6c9 100644 --- a/src/testgen/testgen/Main.hs +++ b/src/testgen/testgen/Main.hs @@ -14,5 +14,19 @@ module Main where +import Java (runJava) +import System.Environment (getArgs) +import System.Exit (ExitCode(ExitFailure), exitWith) +import System.IO (hPutStrLn, stderr) +import TestClass (generateTestClass) + main :: IO () -main = putStrLn "Hello, Haskell!" +main = do + args <- getArgs + case args of + [file] -> do + test <- generateTestClass + writeFile file test + _ -> do + hPutStrLn stderr "Usage: cabal run testgen -- OutputFile.java" + exitWith (ExitFailure 1) From 7aef7aec1dfbed7e4806240014447ed2e8b01977 Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 19:17:35 +0100 Subject: [PATCH 4/7] Integrate new entry point with Gradle --- build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2147b79..52170a8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -112,9 +112,11 @@ pitest { // Test generation tasks.register("generateQuickCheckTests") { + File("src/facadetests/java/MakeItFit").mkdirs() dependsOn(tasks.jar) workingDir = file("src/testgen") - commandLine = listOf("cabal", "run") + commandLine = + listOf("cabal", "run", "testgen", "--", "../facadetests/java/MakeItFit/MakeItFitTest.java") } tasks.register("generateEvoSuiteTests") { From ae2ee10b69d1ae11a2753b7c71a151a01f9ff54f Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 19:17:50 +0100 Subject: [PATCH 5/7] Fix compilation error of generated code --- src/testgen/testgen/TestClass.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/testgen/testgen/TestClass.hs b/src/testgen/testgen/TestClass.hs index 97d0668..76fe043 100644 --- a/src/testgen/testgen/TestClass.hs +++ b/src/testgen/testgen/TestClass.hs @@ -39,8 +39,12 @@ generateUnformattedTestClass = do tests <- generateTests return $ concat - [ [ "import java.util.Arrays;" + [ [ "package MakeItFit;" + , "" + , "import java.util.Arrays;" , "import java.util.List;" + , "import org.junit.jupiter.api.Test;" + , "import static org.junit.jupiter.api.Assertions.*;" , "" , "import MakeItFit.users.User;" , "" From 32d39b04c84507fc755f446d7b2d2920d6a59407 Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 19:23:24 +0100 Subject: [PATCH 6/7] Add Haskell build integration to Gradle --- build.gradle.kts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 52170a8..fc86786 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -142,6 +142,15 @@ tasks.register("generateEvoSuiteTests") { // Other tasks +tasks.named("build") { + finalizedBy(tasks.named("buildHaskell")) +} + +tasks.register("buildHaskell") { + workingDir = file("src/testgen") + commandLine = listOf("cabal", "build") +} + tasks.named("run") { standardInput = System.`in` } From 000669c9c7f31a3f200ddb7a39aea435ef18e75f Mon Sep 17 00:00:00 2001 From: voidbert Date: Tue, 3 Jun 2025 19:30:27 +0100 Subject: [PATCH 7/7] Hopefully fix GitHub Actions --- .github/workflows/maintenance.yaml | 4 ++-- src/testgen/testgen.cabal | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/maintenance.yaml b/.github/workflows/maintenance.yaml index 26023ef..5393e4d 100644 --- a/.github/workflows/maintenance.yaml +++ b/.github/workflows/maintenance.yaml @@ -21,7 +21,7 @@ jobs: sudo bash ./llvm.sh 19 && (sudo rm /usr/bin/clang-format || exit 0) && sudo apt -y install clang-format-19 - - run: gradle format + - run: gradle --no-daemon format build: timeout-minutes: 10 @@ -33,4 +33,4 @@ jobs: java-version: '21' distribution: 'temurin' - - run: ./gradlew --no-daemon build + - run: cabal update && ./gradlew --no-daemon build diff --git a/src/testgen/testgen.cabal b/src/testgen/testgen.cabal index caa9267..66138b1 100644 --- a/src/testgen/testgen.cabal +++ b/src/testgen/testgen.cabal @@ -23,4 +23,4 @@ executable testgen build-depends: base >=4.15.1.0 && <5, QuickCheck ^>=2.15.0.1, - process ^>=1.6.26.1 + process ^>=1.6.25.0