~jan0sch/smederee
Showing details for patch f2403e44057ea4a9534fc86a6d2ac8530baeec00.
diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/tickets/DoobieMilestoneRepositoryTest.scala new-smederee/modules/hub/src/test/scala/de/smederee/tickets/DoobieMilestoneRepositoryTest.scala --- old-smederee/modules/hub/src/test/scala/de/smederee/tickets/DoobieMilestoneRepositoryTest.scala 2025-01-11 00:01:25.713397455 +0000 +++ new-smederee/modules/hub/src/test/scala/de/smederee/tickets/DoobieMilestoneRepositoryTest.scala 2025-01-11 00:01:25.713397455 +0000 @@ -8,13 +8,17 @@ import java.time.* +import cats.data.NonEmptyList import cats.effect.* import cats.syntax.all.* import de.smederee.TestTags.* -import de.smederee.tickets.Generators.* +import de.smederee.tickets.Generators.given import doobie.* +import org.scalacheck.effect.PropF + final class DoobieMilestoneRepositoryTest extends BaseSpec { + override def scalaCheckTestParameters = super.scalaCheckTestParameters.withMinSuccessfulTests(1) /** Find the milestone ID for the given repository and milestone title. * @@ -56,47 +60,47 @@ } test("allMilestones must return all milestones".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestones.sample) match { - case (Some(owner), Some(generatedProject), Some(milestones)) => - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId match { - case None => IO.pure(List.empty) - case Some(repoId) => - milestones.traverse(milestone => milestoneRepo.createMilestone(repoId)(milestone)) - } - foundMilestones <- repoId match { - case None => IO.pure(List.empty) - case Some(repoId) => milestoneRepo.allMilestones(repoId).compile.toList - } - } yield foundMilestones - test.map { foundMilestones => - assert(foundMilestones.size === milestones.size, "Different number of milestones!") - foundMilestones.sortBy(_.title).zip(milestones.sortBy(_.title)).map { (found, expected) => - assertEquals(found.copy(id = expected.id), expected) - } + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestones: NonEmptyList[Milestone]) => + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId match { + case None => IO.pure(List.empty) + case Some(repoId) => + milestones.toList.traverse(milestone => milestoneRepo.createMilestone(repoId)(milestone)) + } + foundMilestones <- repoId match { + case None => IO.pure(List.empty) + case Some(repoId) => milestoneRepo.allMilestones(repoId).compile.toList } - case _ => fail("Could not generate data samples!") + } yield foundMilestones + test.start.flatMap(_.joinWithNever).map { foundMilestones => + assert(foundMilestones.size === milestones.size, "Different number of milestones!") + val cleanedFound = + foundMilestones.sortBy(_.title).zip(milestones.toList.sortBy(_.title)).map { (found, expected) => + found.copy(id = expected.id) + } + assertEquals(cleanedFound.sortBy(_.title), milestones.toList.sortBy(_.title)) + } } } test("allTickets must return all tickets associated with the milestone".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample, genTickets.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone), Some(rawTickets)) => + PropF.forAllF { + (owner: ProjectOwner, generatedProject: Project, milestone: Milestone, rawTickets: NonEmptyList[Ticket]) => val project = generatedProject.copy(owner = owner) - val tickets = rawTickets.map(_.copy(submitter = None)) + val tickets = rawTickets.toList.map(_.copy(submitter = None)) val dbConfig = configuration.database val tx = Transactor.fromDriverManager[IO]( driver = dbConfig.driver, @@ -132,304 +136,286 @@ } yield foundTickets } } yield foundTickets - test.map { foundTickets => + test.start.flatMap(_.joinWithNever).map { foundTickets => assertEquals(foundTickets.size, tickets.size, "Different number of tickets!") - foundTickets.sortBy(_.number).zip(tickets.sortBy(_.number)).map { (found, expected) => - assertEquals( - found.copy(createdAt = expected.createdAt, updatedAt = expected.updatedAt), - expected - ) - } + val cleanedFound = + foundTickets.sortBy(_.number).zip(tickets.sortBy(_.number)).map { (found, expected) => + found.copy(createdAt = expected.createdAt, updatedAt = expected.updatedAt) + } + assertEquals(cleanedFound.sortBy(_.number), tickets.sortBy(_.number)) } - case _ => fail("Could not generate data samples!") } } test("closeMilestone must set the closed flag correctly".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(generatedMilestone)) => - val milestone = generatedMilestone.copy(closed = false) - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - milestones <- repoId match { - case None => IO.pure((None, None)) - case Some(projectId) => - for { - _ <- milestoneRepo.createMilestone(projectId)(milestone) - before <- milestoneRepo.findMilestone(projectId)(milestone.title) - _ <- before.flatMap(_.id).traverse(milestoneRepo.closeMilestone) - after <- milestoneRepo.findMilestone(projectId)(milestone.title) - } yield (before, after) - } - } yield milestones - test.map { result => - val (before, after) = result - val expected = before.map(m => milestone.copy(id = m.id)) - assertEquals(before, expected, "Test milestone not properly initialised!") - assertEquals(after, before.map(_.copy(closed = true)), "Test milestone not properly closed!") + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, generatedMilestone: Milestone) => + val milestone = generatedMilestone.copy(closed = false) + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + milestones <- repoId match { + case None => IO.pure((None, None)) + case Some(projectId) => + for { + _ <- milestoneRepo.createMilestone(projectId)(milestone) + before <- milestoneRepo.findMilestone(projectId)(milestone.title) + _ <- before.flatMap(_.id).traverse(milestoneRepo.closeMilestone) + after <- milestoneRepo.findMilestone(projectId)(milestone.title) + } yield (before, after) } - case _ => fail("Could not generate data samples!") + } yield milestones + test.start.flatMap(_.joinWithNever).map { result => + val (before, after) = result + val expected = before.map(m => milestone.copy(id = m.id)) + assertEquals(before, expected, "Test milestone not properly initialised!") + assertEquals(after, before.map(_.copy(closed = true)), "Test milestone not properly closed!") + } } } test("createMilestone must create the milestone".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone)) => - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(milestone.title)) - } yield (createdRepos, repoId, createdMilestones, foundMilestone) - test.map { tuple => - val (createdRepos, repoId, createdMilestones, foundMilestone) = tuple - assert(createdRepos === 1, "Test vcs generatedProject was not created!") - assert(repoId.nonEmpty, "No vcs generatedProject id found!") - assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") - foundMilestone.getOrElse(None) match { - case None => fail("Created milestone not found!") - case Some(foundMilestone) => - assertEquals(foundMilestone, milestone.copy(id = foundMilestone.id)) - } + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestone: Milestone) => + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(milestone.title)) + } yield (createdRepos, repoId, createdMilestones, foundMilestone) + test.start.flatMap(_.joinWithNever).map { tuple => + val (createdRepos, repoId, createdMilestones, foundMilestone) = tuple + assert(createdRepos === 1, "Test vcs generatedProject was not created!") + assert(repoId.nonEmpty, "No vcs generatedProject id found!") + assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") + foundMilestone.getOrElse(None) match { + case None => fail("Created milestone not found!") + case Some(foundMilestone) => + assertEquals(foundMilestone, milestone.copy(id = foundMilestone.id)) } - case _ => fail("Could not generate data samples!") + } } } test("createMilestone must fail if the milestone name already exists".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone)) => - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - _ <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - } yield (createdRepos, repoId, createdMilestones) - test.attempt.map(r => assert(r.isLeft, "Creating a milestone with a duplicate name must fail!")) - case _ => fail("Could not generate data samples!") + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestone: Milestone) => + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + _ <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + } yield (createdRepos, repoId, createdMilestones) + test.attempt.map(r => assert(r.isLeft, "Creating a milestone with a duplicate name must fail!")) } } test("deleteMilestone must delete an existing milestone".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone)) => - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) - deletedMilestones <- milestoneRepo.deleteMilestone( - milestone.copy(id = milestoneId.flatMap(MilestoneId.from)) - ) - foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(milestone.title)) - } yield (createdRepos, repoId, createdMilestones, deletedMilestones, foundMilestone) - test.map { tuple => - val (createdRepos, repoId, createdMilestones, deletedMilestones, foundMilestone) = tuple - assert(createdRepos === 1, "Test vcs generatedProject was not created!") - assert(repoId.nonEmpty, "No vcs generatedProject id found!") - assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") - assert(deletedMilestones === 1, "Test milestone was not deleted!") - assert(foundMilestone.getOrElse(None).isEmpty, "Test milestone was not deleted!") - } - case _ => fail("Could not generate data samples!") + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestone: Milestone) => + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) + deletedMilestones <- milestoneRepo.deleteMilestone( + milestone.copy(id = milestoneId.flatMap(MilestoneId.from)) + ) + foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(milestone.title)) + } yield (createdRepos, repoId, createdMilestones, deletedMilestones, foundMilestone) + test.start.flatMap(_.joinWithNever).map { tuple => + val (createdRepos, repoId, createdMilestones, deletedMilestones, foundMilestone) = tuple + assert(createdRepos === 1, "Test vcs generatedProject was not created!") + assert(repoId.nonEmpty, "No vcs generatedProject id found!") + assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") + assert(deletedMilestones === 1, "Test milestone was not deleted!") + assert(foundMilestone.getOrElse(None).isEmpty, "Test milestone was not deleted!") + } } } test("findMilestone must find existing milestones".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestones.sample) match { - case (Some(owner), Some(generatedProject), Some(milestones)) => - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val expectedMilestone = milestones(scala.util.Random.nextInt(milestones.size)) - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId match { - case None => IO.pure(List.empty) - case Some(repoId) => - milestones.traverse(milestone => milestoneRepo.createMilestone(repoId)(milestone)) - } - foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(expectedMilestone.title)) - } yield foundMilestone.flatten - test.map { foundMilestone => - assertEquals(foundMilestone.map(_.copy(id = expectedMilestone.id)), Option(expectedMilestone)) + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestones: NonEmptyList[Milestone]) => + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val expectedMilestone = milestones.toList(scala.util.Random.nextInt(milestones.size)) + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId match { + case None => IO.pure(List.empty) + case Some(repoId) => + milestones.toList.traverse(milestone => milestoneRepo.createMilestone(repoId)(milestone)) } - case _ => fail("Could not generate data samples!") + foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(expectedMilestone.title)) + } yield foundMilestone.flatten + test.start.flatMap(_.joinWithNever).map { foundMilestone => + assertEquals(foundMilestone.map(_.copy(id = expectedMilestone.id)), Option(expectedMilestone)) + } } } test("openMilestone must reset the closed flag correctly".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(generatedMilestone)) => - val milestone = generatedMilestone.copy(closed = true) - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - milestones <- repoId match { - case None => IO.pure((None, None)) - case Some(projectId) => - for { - _ <- milestoneRepo.createMilestone(projectId)(milestone) - before <- milestoneRepo.findMilestone(projectId)(milestone.title) - _ <- before.flatMap(_.id).traverse(milestoneRepo.openMilestone) - after <- milestoneRepo.findMilestone(projectId)(milestone.title) - } yield (before, after) - } - } yield milestones - test.map { result => - val (before, after) = result - val expected = before.map(m => milestone.copy(id = m.id)) - assertEquals(before, expected, "Test milestone not properly initialised!") - assertEquals(after, before.map(_.copy(closed = false)), "Test milestone not properly opened!") + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, generatedMilestone: Milestone) => + val milestone = generatedMilestone.copy(closed = true) + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + milestones <- repoId match { + case None => IO.pure((None, None)) + case Some(projectId) => + for { + _ <- milestoneRepo.createMilestone(projectId)(milestone) + before <- milestoneRepo.findMilestone(projectId)(milestone.title) + _ <- before.flatMap(_.id).traverse(milestoneRepo.openMilestone) + after <- milestoneRepo.findMilestone(projectId)(milestone.title) + } yield (before, after) } - case _ => fail("Could not generate data samples!") + } yield milestones + test.start.flatMap(_.joinWithNever).map { result => + val (before, after) = result + val expected = before.map(m => milestone.copy(id = m.id)) + assertEquals(before, expected, "Test milestone not properly initialised!") + assertEquals(after, before.map(_.copy(closed = false)), "Test milestone not properly opened!") + } } } test("updateMilestone must update an existing milestone".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone)) => - val updatedMilestone = milestone.copy( - title = MilestoneTitle("updated milestone"), - description = Option(MilestoneDescription("I am an updated milestone description...")), - dueDate = Option(LocalDate.of(1879, 3, 14)) - ) - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) - updatedMilestones <- milestoneRepo.updateMilestone( - updatedMilestone.copy(id = milestoneId.map(MilestoneId.apply)) - ) - foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(updatedMilestone.title)) - } yield (createdRepos, repoId, createdMilestones, updatedMilestones, foundMilestone.flatten) - test.map { tuple => - val (createdRepos, repoId, createdMilestones, updatedMilestones, foundMilestone) = tuple - assert(createdRepos === 1, "Test vcs generatedProject was not created!") - assert(repoId.nonEmpty, "No vcs generatedProject id found!") - assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") - assert(updatedMilestones === 1, "Test milestone was not updated!") - assert(foundMilestone.nonEmpty, "Updated milestone not found!") - foundMilestone.map { milestone => - assertEquals(milestone, updatedMilestone.copy(id = milestone.id)) - } + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestone: Milestone) => + val updatedMilestone = milestone.copy( + title = MilestoneTitle("updated milestone"), + description = Option(MilestoneDescription("I am an updated milestone description...")), + dueDate = Option(LocalDate.of(1879, 3, 14)) + ) + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) + updatedMilestones <- milestoneRepo.updateMilestone( + updatedMilestone.copy(id = milestoneId.map(MilestoneId.apply)) + ) + foundMilestone <- repoId.traverse(id => milestoneRepo.findMilestone(id)(updatedMilestone.title)) + } yield (createdRepos, repoId, createdMilestones, updatedMilestones, foundMilestone.flatten) + test.start.flatMap(_.joinWithNever).map { tuple => + val (createdRepos, repoId, createdMilestones, updatedMilestones, foundMilestone) = tuple + assert(createdRepos === 1, "Test vcs generatedProject was not created!") + assert(repoId.nonEmpty, "No vcs generatedProject id found!") + assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") + assert(updatedMilestones === 1, "Test milestone was not updated!") + assert(foundMilestone.nonEmpty, "Updated milestone not found!") + foundMilestone.foreach { milestone => + assertEquals(milestone, updatedMilestone.copy(id = milestone.id)) } - case _ => fail("Could not generate data samples!") + } } } test("updateMilestone must do nothing if id attribute is empty".tag(NeedsDatabase)) { - (genProjectOwner.sample, genProject.sample, genMilestone.sample) match { - case (Some(owner), Some(generatedProject), Some(milestone)) => - val updatedMilestone = milestone.copy( - id = None, - title = MilestoneTitle("updated milestone"), - description = Option(MilestoneDescription("I am an updated milestone description...")), - dueDate = Option(LocalDate.of(1879, 3, 14)) - ) - val project = generatedProject.copy(owner = owner) - val dbConfig = configuration.database - val tx = Transactor.fromDriverManager[IO]( - driver = dbConfig.driver, - url = dbConfig.url, - user = dbConfig.user, - password = dbConfig.pass, - logHandler = None - ) - val milestoneRepo = new DoobieMilestoneRepository[IO](tx) - val test = for { - _ <- createProjectOwner(owner) - createdRepos <- createTicketsProject(project) - repoId <- loadProjectId(owner.uid, project.name) - createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) - milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) - updatedMilestones <- milestoneRepo.updateMilestone(updatedMilestone) - } yield (createdRepos, repoId, createdMilestones, updatedMilestones) - test.map { tuple => - val (createdRepos, repoId, createdMilestones, updatedMilestones) = tuple - assert(createdRepos === 1, "Test vcs generatedProject was not created!") - assert(repoId.nonEmpty, "No vcs generatedProject id found!") - assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") - assert(updatedMilestones === 0, "Milestone with empty id must not be updated!") - } - case _ => fail("Could not generate data samples!") + PropF.forAllF { (owner: ProjectOwner, generatedProject: Project, milestone: Milestone) => + val updatedMilestone = milestone.copy( + id = None, + title = MilestoneTitle("updated milestone"), + description = Option(MilestoneDescription("I am an updated milestone description...")), + dueDate = Option(LocalDate.of(1879, 3, 14)) + ) + val project = generatedProject.copy(owner = owner) + val dbConfig = configuration.database + val tx = Transactor.fromDriverManager[IO]( + driver = dbConfig.driver, + url = dbConfig.url, + user = dbConfig.user, + password = dbConfig.pass, + logHandler = None + ) + val milestoneRepo = new DoobieMilestoneRepository[IO](tx) + val test = for { + _ <- createProjectOwner(owner) + createdRepos <- createTicketsProject(project) + repoId <- loadProjectId(owner.uid, project.name) + createdMilestones <- repoId.traverse(id => milestoneRepo.createMilestone(id)(milestone)) + milestoneId <- findMilestoneId(owner.uid, project.name, milestone.title) + updatedMilestones <- milestoneRepo.updateMilestone(updatedMilestone) + } yield (createdRepos, repoId, createdMilestones, updatedMilestones) + test.start.flatMap(_.joinWithNever).map { tuple => + val (createdRepos, repoId, createdMilestones, updatedMilestones) = tuple + assert(createdRepos === 1, "Test vcs generatedProject was not created!") + assert(repoId.nonEmpty, "No vcs generatedProject id found!") + assert(createdMilestones.exists(_ === 1), "Test milestone was not created!") + assert(updatedMilestones === 0, "Milestone with empty id must not be updated!") + } } } } diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/tickets/Generators.scala new-smederee/modules/hub/src/test/scala/de/smederee/tickets/Generators.scala --- old-smederee/modules/hub/src/test/scala/de/smederee/tickets/Generators.scala 2025-01-11 00:01:25.713397455 +0000 +++ new-smederee/modules/hub/src/test/scala/de/smederee/tickets/Generators.scala 2025-01-11 00:01:25.717397462 +0000 @@ -141,6 +141,8 @@ updatedAt ) + given Arbitrary[Ticket] = Arbitrary(genTicket) + val genTickets: Gen[List[Ticket]] = Gen.nonEmptyListOf(genTicket) .map(_.zipWithIndex.map(tuple => tuple._1.copy(number = TicketNumber(tuple._2 + 1)))) @@ -229,6 +231,8 @@ closed <- Gen.oneOf(List(false, true)) } yield Milestone(id, title, descr, due, closed) + given Arbitrary[Milestone] = Arbitrary(genMilestone) + val genMilestones: Gen[List[Milestone]] = Gen.nonEmptyListOf(genMilestone).map(_.distinct) val genProjectName: Gen[ProjectName] = Gen