Skip to content

Commit

Permalink
feat(server): Add unit tests in CompanyService (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevchuang authored May 9, 2024
1 parent e1dae70 commit 7fcb1df
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package io.kevchuang.reviewboard.domain

import io.github.iltotore.iron.constraint.all.*
import io.github.iltotore.iron.zioJson.given
import zio.*
import zio.json.*
import io.github.iltotore.iron.*
import io.kevchuang.reviewboard.domain.error.DomainError
import io.kevchuang.reviewboard.services.db.DatabaseService
import io.kevchuang.reviewboard.types.{NotEmpty, OnlyLetters}
import sttp.tapir.Schema
import sttp.tapir.generic.auto.*
Expand Down Expand Up @@ -59,7 +61,43 @@ object company:
industry: Option[IndustryName] = None,
image: Option[Url] = None,
tags: List[TagName] = List.empty[TagName]
)
):
private def generateCompanySlug: CompanySlug =
CompanySlug(
name
.replaceAll(" +", " ")
.split(" ")
.map(_.toLowerCase)
.mkString("-")
.assume[NotEmpty]
)

private def generateCompanyId
: ZIO[DatabaseService, UnableToGenerateCompanyId, CompanyId] =
DatabaseService.countCompanies.flatMap(id =>
ZIO
.fromEither((id + 1).refineEither[Positive])
.mapBoth(
error => UnableToGenerateCompanyId(error),
companyId => CompanyId(companyId)
)
)

def toCompany: ZIO[DatabaseService, UnableToGenerateCompanyId, Company] =
generateCompanyId.map: companyId =>
Company(
id = companyId,
slug = generateCompanySlug,
name = name,
url = url,
location = location,
country = country,
industry = industry,
image = image,
tags = tags
)
end CreateCompany

object CreateCompany:
given JsonCodec[CreateCompany] = DeriveJsonCodec.gen[CreateCompany]
inline given Schema[CreateCompany] = Schema.derived[CreateCompany]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.kevchuang.reviewboard.http.routes

import sttp.tapir.server.ServerEndpoint
import sttp.tapir.server.ziohttp.{ZioHttpInterpreter, ZioHttpServerOptions}
import sttp.tapir.server.ziohttp.ZioHttpInterpreter
import sttp.tapir.ztapir.ZServerEndpoint
import zio.*
import zio.http.HttpApp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,18 @@ import io.kevchuang.reviewboard.domain.company.*
import io.kevchuang.reviewboard.services.db.DatabaseService
import zio.*
import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*
import io.kevchuang.reviewboard.types.NotEmpty

object CompanyServiceLive:
lazy val live: ULayer[CompanyService] = ZLayer.succeed(
new CompanyService:
private def generateCompanyId
: ZIO[DatabaseService, UnableToGenerateCompanyId, CompanyId] =
DatabaseService.countCompanies
.flatMap: id =>
ZIO
.fromEither(id.refineEither[Positive])
.mapBoth(
error => UnableToGenerateCompanyId(error),
companyId => CompanyId(companyId)
)

private def generateCompanySlug(
companyName: CompanyName
): UIO[CompanySlug] =
ZIO.succeed(
CompanySlug(
companyName
.replaceAll(" +", " ")
.split(" ")
.map(_.toLowerCase)
.mkString("-")
.assume[NotEmpty]
)
)

private def generateCompany(
company: CreateCompany
): ZIO[DatabaseService, UnableToGenerateCompanyId, Company] =
for
companyId <- generateCompanyId
companySlug <- generateCompanySlug(company.name)
yield Company(
id = companyId,
slug = companySlug,
name = company.name,
url = company.url,
location = company.location,
country = company.country,
industry = company.industry,
image = company.image,
tags = company.tags
)

override def createCompany(
company: CreateCompany
): ZIO[DatabaseService, CompanyDomainError, Company] =
DatabaseService
.existsCompany(company.name)
.flatMap: exists =>
if exists then ZIO.fail(CompanyAlreadyExists(company.name))
else generateCompany(company).tap(DatabaseService.insertCompany)
for
exists <- DatabaseService.existsCompany(company.name)
_ <- ZIO.fail(CompanyAlreadyExists(company.name)).unless(!exists)
companyToInsert <- company.toCompany
_ <- DatabaseService.insertCompany(companyToInsert)
yield companyToInsert
)
end CompanyServiceLive
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.kevchuang.reviewboard.services.company

import io.kevchuang.reviewboard.domain.company.*
import io.kevchuang.reviewboard.services.utils.DataGenerator
import zio.Scope
import zio.test.*
import io.github.iltotore.iron.*
import io.kevchuang.reviewboard.services.db.{DatabaseService, InMemoryDatabase}

object CompanyServiceSpec extends ZIOSpecDefault:
override def spec: Spec[TestEnvironment with Scope, Any] = createCompanySuite

private lazy val createCompanySuite =
suite("createCompany")(
test("should create and add a new Company to the database") {
val companyName = CompanyName("Contentsquare")
val companyUrl = Url("contentsquare.com")
val createCompany =
DataGenerator.generateCreateCompany(companyName, companyUrl)
val expected = DataGenerator.generateCompany(
id = CompanyId(1),
slug = CompanySlug("contentsquare"),
name = companyName,
url = companyUrl
)
for
company <- CompanyService.createCompany(createCompany)
exists <- DatabaseService.existsCompany(companyName)
yield assertTrue(company == expected, exists)
end for
}.provide(InMemoryDatabase.live, CompanyServiceLive.live)
)
end CompanyServiceSpec
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.kevchuang.reviewboard.services.utils

import io.kevchuang.reviewboard.domain.company.*

object DataGenerator:
def generateCreateCompany(
name: CompanyName,
url: Url,
location: Option[LocationName] = None,
country: Option[CountryName] = None,
industry: Option[IndustryName] = None,
image: Option[Url] = None,
tags: List[TagName] = List.empty[TagName]
): CreateCompany =
CreateCompany(
name = name,
url = url,
location = location,
country = country,
industry = industry,
image = image,
tags = tags
)

def generateCompany(
id: CompanyId,
slug: CompanySlug,
name: CompanyName,
url: Url,
location: Option[LocationName] = None,
country: Option[CountryName] = None,
industry: Option[IndustryName] = None,
image: Option[Url] = None,
tags: List[TagName] = List.empty[TagName]
): Company = Company(
id = id,
slug = slug,
name = name,
url = url,
location = location,
country = country,
industry = industry,
image = image,
tags = tags
)
end DataGenerator

0 comments on commit 7fcb1df

Please sign in to comment.