From 16a7fd9aec741e491a585fa93373d6f56eb1ef2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lopes?= Date: Wed, 4 Jun 2025 23:18:22 +0100 Subject: [PATCH] user tests generation --- src/testgen/testgen/FacadeTemplates.hs | 299 ++++++++++++++++++++++++- src/testgen/testgen/Generators.hs | 7 +- src/testgen/testgen/TestClass.hs | 12 +- 3 files changed, 312 insertions(+), 6 deletions(-) diff --git a/src/testgen/testgen/FacadeTemplates.hs b/src/testgen/testgen/FacadeTemplates.hs index 8d38933..f46d278 100644 --- a/src/testgen/testgen/FacadeTemplates.hs +++ b/src/testgen/testgen/FacadeTemplates.hs @@ -15,6 +15,16 @@ module FacadeTemplates ( equalityTemplate, emailTemplate, + createAndGetUserTemplate, + removeUserByEmailTemplate, + removeUserByUUIDTemplate, + removeUserInvalidTypeTemplate, + getUserInvalidTypeTemplate, + removeNonExistentUserTemplate, + updateUserTemplate, + updateEmailTemplate, + duplicateUserTemplate, + getAllUsersTemplate, getActivitiesFromUserTemplate, addActivityToUserTemplate, removeActivityFromUserTemplate, @@ -36,7 +46,7 @@ module FacadeTemplates ( import Java (assertEquals, assertTrue, runJava, toJavaExpression, toJavaExpressionList, JavaData (toJavaExpression), assertThrows) import TestTemplate (TestTemplate(..), genToTestTemplate) -import Test.QuickCheck (Gen, arbitrary, elements, generate, listOf, Arbitrary (arbitrary)) +import Test.QuickCheck (Gen, arbitrary, elements, choose, generate, listOf, Arbitrary (arbitrary), suchThat) import Generators import Data.List (intercalate) import GHC.Generics (Associativity) @@ -93,6 +103,289 @@ userCodeActivity userCode (Running _ a b c d e f) = Running userCode a b c d e f userCodeActivity userCode (Trail _ a b c d e f g h) = Trail userCode a b c d e f g h userCodeActivity userCode (WeightSquat _ a b c d e f g) = WeightSquat userCode a b c d e f g +userName :: User -> String +userName (Amateur name _ _ _ _ _ _ _ _ _ _) = name +userName (Occasional name _ _ _ _ _ _ _ _ _ _ _) = name +userName (Professional name _ _ _ _ _ _ _ _ _ _ _) = name + +userAge :: User -> Int +userAge (Amateur _ age _ _ _ _ _ _ _ _ _) = age +userAge (Occasional _ age _ _ _ _ _ _ _ _ _ _) = age +userAge (Professional _ age _ _ _ _ _ _ _ _ _ _) = age + +userGender :: User -> Gender +userGender (Amateur _ _ gender _ _ _ _ _ _ _ _) = gender +userGender (Occasional _ _ gender _ _ _ _ _ _ _ _ _) = gender +userGender (Professional _ _ gender _ _ _ _ _ _ _ _ _) = gender + +userWeight :: User -> Int +userWeight (Amateur _ _ _ weight _ _ _ _ _ _ _) = weight +userWeight (Occasional _ _ _ weight _ _ _ _ _ _ _ _) = weight +userWeight (Professional _ _ _ weight _ _ _ _ _ _ _ _) = weight + +userHeight :: User -> Int +userHeight (Amateur _ _ _ _ height _ _ _ _ _ _) = height +userHeight (Occasional _ _ _ _ height _ _ _ _ _ _ _) = height +userHeight (Professional _ _ _ _ height _ _ _ _ _ _ _) = height + +userBpm :: User -> Int +userBpm (Amateur _ _ _ _ _ bpm _ _ _ _ _) = bpm +userBpm (Occasional _ _ _ _ _ bpm _ _ _ _ _ _) = bpm +userBpm (Professional _ _ _ _ _ bpm _ _ _ _ _ _) = bpm + +userLevel :: User -> Int +userLevel (Amateur _ _ _ _ _ _ level _ _ _ _) = level +userLevel (Occasional _ _ _ _ _ _ level _ _ _ _ _) = level +userLevel (Professional _ _ _ _ _ _ level _ _ _ _ _) = level + +userAddress :: User -> String +userAddress (Amateur _ _ _ _ _ _ _ address _ _ _) = address +userAddress (Occasional _ _ _ _ _ _ _ address _ _ _ _) = address +userAddress (Professional _ _ _ _ _ _ _ address _ _ _ _) = address + +userPhone :: User -> String +userPhone (Amateur _ _ _ _ _ _ _ _ phone _ _) = phone +userPhone (Occasional _ _ _ _ _ _ _ _ phone _ _ _) = phone +userPhone (Professional _ _ _ _ _ _ _ _ phone _ _ _) = phone + +-- testCreateAndGetUser +testCreateAndGetUserGenerator :: Gen [String] +testCreateAndGetUserGenerator = do + user <- arbitrary :: Gen User + let name = userName user + age = userAge user + email = userEmail user + setupLine = "MakeItFit model = new MakeItFit();" + createUserLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + existsLine = "assertTrue(model.existsUserWithEmail(" ++ toJavaExpression email ++ "));" + getUserLine = "User user = model.getUser(" ++ toJavaExpression email ++ ");" + assertNameLine = "assertEquals(" ++ toJavaExpression name ++ ", user.getName());" + assertAgeLine = "assertEquals(" ++ show age ++ ", user.getAge());" + return + [ setupLine + , createUserLine + , existsLine + , getUserLine + , assertNameLine + , assertAgeLine + ] + +createAndGetUserTemplate :: TestTemplate +createAndGetUserTemplate = + genToTestTemplate "testCreateAndGetUser" testCreateAndGetUserGenerator 1 + +-- testRemoveUserByEmail +testRemoveUserByEmailGenerator :: Gen [String] +testRemoveUserByEmailGenerator = do + user <- arbitrary :: Gen User + let email = userEmail user + setupLine = "MakeItFit model = new MakeItFit();" + createLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + removeLine = "model.removeUser(" ++ toJavaExpression email ++ ");" + assertLine = "assertFalse(model.existsUserWithEmail(" ++ toJavaExpression email ++ "));" + return [ setupLine, createLine, removeLine, assertLine ] + +removeUserByEmailTemplate :: TestTemplate +removeUserByEmailTemplate = + genToTestTemplate "testRemoveUserByEmail" testRemoveUserByEmailGenerator 1 + +-- testRemoveUserByUUID +testRemoveUserByUUIDGenerator :: Gen [String] +testRemoveUserByUUIDGenerator = do + user <- arbitrary :: Gen User + let email = userEmail user + createArgs = toJavaCreateUserArgs user + setupLine = "MakeItFit model = new MakeItFit();" + createLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + getIdLine = "UUID id = model.getUser(" ++ toJavaExpression email ++ ").getCode();" + removeLine = "model.removeUser(id);" + assertLine = "assertFalse(model.existsUserWithEmail(" ++ toJavaExpression email ++ "));" + return [ setupLine, createLine, getIdLine, removeLine, assertLine ] + +removeUserByUUIDTemplate :: TestTemplate +removeUserByUUIDTemplate = + genToTestTemplate "testRemoveUserByUUID" testRemoveUserByUUIDGenerator 1 + +-- testRemoveUserInvalidTypeGenerator +testRemoveUserInvalidTypeGenerator :: Gen [String] +testRemoveUserInvalidTypeGenerator = do + let setupLine = "MakeItFit model = new MakeItFit();" + assertLine = "assertThrows(InvalidTypeException.class, () -> model.removeUser(123));" + return [ setupLine, assertLine ] + +removeUserInvalidTypeTemplate :: TestTemplate +removeUserInvalidTypeTemplate = + genToTestTemplate "testRemoveUserInvalidType" testRemoveUserInvalidTypeGenerator 1 + +-- testGetUserInvalidTypeGenerator +testGetUserInvalidTypeGenerator :: Gen [String] +testGetUserInvalidTypeGenerator = do + let setupLine = "MakeItFit model = new MakeItFit();" + assertLine = "assertThrows(InvalidTypeException.class, () -> model.getUser(123));" + return [ setupLine, assertLine ] + +getUserInvalidTypeTemplate :: TestTemplate +getUserInvalidTypeTemplate = + genToTestTemplate "testGetUserInvalidType" testGetUserInvalidTypeGenerator 1 + +-- testRemoveNonExistentUserGenerator +testRemoveNonExistentUserGenerator :: Gen [String] +testRemoveNonExistentUserGenerator = do + email <- genEmail + let setupLine = "MakeItFit model = new MakeItFit();" + assertLine = "assertThrows(EntityDoesNotExistException.class, () -> model.removeUser(" ++ toJavaExpression email ++ "));" + return [ setupLine, assertLine ] + +removeNonExistentUserTemplate :: TestTemplate +removeNonExistentUserTemplate = + genToTestTemplate "testRemoveNonExistentUser" testRemoveNonExistentUserGenerator 1 + +-- testUpdateUser +testUpdateUserGenerator :: Gen [String] +testUpdateUserGenerator = do + user <- arbitrary :: Gen User + let email = userEmail user + + newName <- genUserName `suchThat` (/= userName user) + newAge <- (choose (18, 80) :: Gen Int) `suchThat` (/= userAge user) + newGender <- (arbitrary :: Gen Gender) `suchThat` (/= userGender user) + newWeight <- (elements [50..100] :: Gen Int) `suchThat` (/= userWeight user) + newHeight <- (choose (150, 195) :: Gen Int) `suchThat` (/= userHeight user) + newBpm <- (choose (60, 100) :: Gen Int) `suchThat` (/= userBpm user) + newLevel <- (choose (1, 10) :: Gen Int) `suchThat` (/= userLevel user) + newAddress <- (genAddress) `suchThat` (/= userAddress user) + newPhone <- genPhone `suchThat` (/= userPhone user) + + let setupLine = "MakeItFit model = new MakeItFit();" + createLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + updNameLine = "model.updateUserName(" ++ toJavaExpression newName ++ ", " ++ toJavaExpression email ++ ");" + updAgeLine = "model.updateUserAge(" ++ show newAge ++ ", " ++ toJavaExpression email ++ ");" + updGenderLine = "model.updateUserGender(" ++ toJavaExpression newGender ++ ", " ++ toJavaExpression email ++ ");" + updWeightLine = "model.updateUserWeight(" ++ show newWeight ++ "f, " ++ toJavaExpression email ++ ");" + updHeightLine = "model.updateUserHeight(" ++ show newHeight ++ ", " ++ toJavaExpression email ++ ");" + updBpmLine = "model.updateUserBpm(" ++ show newBpm ++ ", " ++ toJavaExpression email ++ ");" + updLevelLine = "model.updateUserLevel(" ++ show newLevel ++ ", " ++ toJavaExpression email ++ ");" + updAddrLine = "model.updateUserAddress("++ toJavaExpression newAddress ++ ", " ++ toJavaExpression email ++ ");" + updPhoneLine = "model.updateUserPhone(" ++ toJavaExpression newPhone ++ ", " ++ toJavaExpression email ++ ");" + getUpdatedByEmailLine = "User updated = model.getUser(" ++ toJavaExpression email ++ ");" + getCodeLine = "UUID id = updated.getCode();" + getByIdLine = "User u = model.getUser(id);" + assertName1 = "assertEquals(" ++ toJavaExpression newName ++ ", u.getName());" + assertName2 = "assertEquals(" ++ toJavaExpression newName ++ ", updated.getName());" + assertAge = "assertEquals(" ++ show newAge ++ ", updated.getAge());" + assertGender = "assertEquals(" ++ toJavaExpression newGender ++ ", updated.getGender());" + assertWeight = "assertEquals(" ++ show newWeight ++ "f, updated.getWeight());" + assertHeight = "assertEquals(" ++ show newHeight ++ ", updated.getHeight());" + assertBpm = "assertEquals(" ++ show newBpm ++ ", updated.getBpm());" + assertLevel = "assertEquals(" ++ show newLevel ++ ", updated.getLevel());" + assertAddress = "assertEquals(" ++ toJavaExpression newAddress ++ ", updated.getAddress());" + assertPhone = "assertEquals(" ++ toJavaExpression newPhone ++ ", updated.getPhone());" + + return + [ setupLine + , createLine + , updNameLine + , updAgeLine + , updGenderLine + , updWeightLine + , updHeightLine + , updBpmLine + , updLevelLine + , updAddrLine + , updPhoneLine + , getUpdatedByEmailLine + , getCodeLine + , getByIdLine + , assertName1 + , assertName2 + , assertAge + , assertGender + , assertWeight + , assertHeight + , assertBpm + , assertLevel + , assertAddress + , assertPhone + ] + +updateUserTemplate :: TestTemplate +updateUserTemplate = + genToTestTemplate "testUpdateUser" testUpdateUserGenerator 1 + +-- testUpdateEmail +testUpdateEmailGenerator :: Gen [String] +testUpdateEmailGenerator = do + user <- arbitrary :: Gen User + let oldEmail = userEmail user + oldNoSp = filter (/= ' ') oldEmail + newEmail <- genEmail `suchThat` (/= oldEmail) + let newNoSp = filter (/= ' ') newEmail + setupLine = "MakeItFit model = new MakeItFit();" + createLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + updEmailLine = "model.updateUserEmail(" ++ toJavaExpression oldNoSp ++ ", " ++ toJavaExpression newNoSp ++ ");" + assertOldGone = "assertFalse(model.existsUserWithEmail(" ++ toJavaExpression oldNoSp ++ "));" + assertNewThere = "assertTrue(model.existsUserWithEmail(" ++ toJavaExpression newNoSp ++ "));" + getUserLine = "User user = model.getUser(" ++ toJavaExpression newNoSp ++ ");" + assertNameLine = "assertEquals(" ++ toJavaExpression (userName user) ++ ", user.getName());" + + return + [ setupLine + , createLine + , updEmailLine + , assertOldGone + , assertNewThere + , getUserLine + , assertNameLine + ] + +updateEmailTemplate :: TestTemplate +updateEmailTemplate = + genToTestTemplate "testUpdateEmail" testUpdateEmailGenerator 1 + +-- testDuplicateUser +testDuplicateUserGenerator :: Gen [String] +testDuplicateUserGenerator = do + user <- arbitrary :: Gen User + let setupLine = "MakeItFit model = new MakeItFit();" + firstCreate = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + assertLine = "assertThrows(ExistingEntityConflictException.class, () -> model.createUser(" ++ toJavaCreateUserArgs user ++ "));" + return [ setupLine, firstCreate, assertLine ] + +duplicateUserTemplate :: TestTemplate +duplicateUserTemplate = + genToTestTemplate "testDuplicateUser" testDuplicateUserGenerator 1 + +-- testGetAllUsers +testGetAllUsersGenerator :: Gen [String] +testGetAllUsersGenerator = do + user <- arbitrary :: Gen User + let email = userEmail user + createArgs = toJavaCreateUserArgs user + + setupLine = "MakeItFit model = new MakeItFit();" + getAll1 = "List allUsers = model.getAllUsers();" + assertNotNull = "assertNotNull(allUsers);" + assertEmpty = "assertTrue(allUsers.isEmpty());" + createLine = "model.createUser(" ++ toJavaCreateUserArgs user ++ ");" + getAll2 = "allUsers = model.getAllUsers();" + collectEmails = "List emails = allUsers.stream().map(User::getEmail).collect(Collectors.toList());" + assertContains = "assertTrue(emails.contains(" ++ toJavaExpression email ++ "));" + + return + [ setupLine + , getAll1 + , assertNotNull + , assertEmpty + , createLine + , getAll2 + , collectEmails + , assertContains + ] + +getAllUsersTemplate :: TestTemplate +getAllUsersTemplate = + genToTestTemplate "testGetAllUsers" testGetAllUsersGenerator 1 + getActivitiesFromUserTestGenerator :: Gen [String] getActivitiesFromUserTestGenerator = do user <- arbitrary :: Gen User @@ -296,7 +589,7 @@ removeTrainingPlanTestGenerator = do let dateLine = "MakeItFitDate startDate = " ++ toJavaExpression date ++ ";" let planCodeLine = "UUID planCode = model.createTrainingPlan(userCode, startDate);" let removeLine = "model.removeTrainingPlan(planCode);" - let assertLine = assertThrows "IllegalArgumentException" ["model.getTrainingPlan(planCode);"] + let assertLine = assertThrows "EntityDoesNotExistException" ["model.getTrainingPlan(planCode);"] return ([setupLine , userLine @@ -343,7 +636,7 @@ getTrainingPlanExceptionTestGenerator :: Gen [String] getTrainingPlanExceptionTestGenerator = do let setupLine = "MakeItFit model = new MakeItFit();" let invalidCodeLine = "UUID invalidCode = UUID.randomUUID();" - let assertLine = assertThrows "IllegalArgumentException" ["model.getTrainingPlan(invalidCode);"] + let assertLine = assertThrows "EntityDoesNotExistException" ["model.getTrainingPlan(invalidCode);"] return ([ setupLine ,invalidCodeLine] ++ assertLine) diff --git a/src/testgen/testgen/Generators.hs b/src/testgen/testgen/Generators.hs index a2b5aae..fdcde3c 100644 --- a/src/testgen/testgen/Generators.hs +++ b/src/testgen/testgen/Generators.hs @@ -22,8 +22,11 @@ module Generators , Activity(..) , TrainingPlan(..) , genActivity - , genTrainingPlan, - toJavaCreateUserArgs + , genTrainingPlan + , toJavaCreateUserArgs + , genAddress + , genPhone + , genUserName ) where import Data.List (intercalate) diff --git a/src/testgen/testgen/TestClass.hs b/src/testgen/testgen/TestClass.hs index 15be59f..067fb29 100644 --- a/src/testgen/testgen/TestClass.hs +++ b/src/testgen/testgen/TestClass.hs @@ -25,7 +25,16 @@ import Control.Exception (bracket, evaluate) import FacadeTemplates templates = - [ + [ createAndGetUserTemplate, + removeUserByEmailTemplate, + removeUserByUUIDTemplate, + removeUserInvalidTypeTemplate, + getUserInvalidTypeTemplate, + removeNonExistentUserTemplate, + updateUserTemplate, + updateEmailTemplate, + duplicateUserTemplate, + getAllUsersTemplate, getActivitiesFromUserTemplate, addActivityToUserTemplate, removeActivityFromUserTemplate, @@ -64,6 +73,7 @@ generateUnformattedTestClass = do , "import MakeItFit.users.User;" , "import MakeItFit.users.Gender;" , "import java.util.UUID;" + , "import java.util.stream.Collectors;" , "import MakeItFit.activities.Activity;" , "import MakeItFit.activities.implementation.*;" , "import MakeItFit.utils.MakeItFitDate;"