diff --git a/src/test/scala/org/chepiov/tomodoro/interpreters/InterpreterSpec.scala b/src/test/scala/org/chepiov/tomodoro/interpreters/InterpreterSpec.scala index b00e684..b9aa891 100644 --- a/src/test/scala/org/chepiov/tomodoro/interpreters/InterpreterSpec.scala +++ b/src/test/scala/org/chepiov/tomodoro/interpreters/InterpreterSpec.scala @@ -1,15 +1,17 @@ package org.chepiov.tomodoro.interpreters +import java.time.OffsetDateTime import java.util.concurrent.Executors -import cats.effect.{Clock, IO, Timer} import cats.effect.concurrent.Ref +import cats.effect.{Clock, IO, Timer} import cats.syntax.applicative._ import cats.syntax.functor._ import cats.syntax.option._ +import org.chepiov.tomodoro.algebras.Repository.ActivityLog import org.chepiov.tomodoro.algebras.Telegram.{TCallbackAnswer, TEditMessage, TSendMessage, TUser} import org.chepiov.tomodoro.algebras.User.{UserCommand, UserInfoQuery} -import org.chepiov.tomodoro.algebras.{Statistic, Telegram, User, Users} +import org.chepiov.tomodoro.algebras._ import scala.concurrent.ExecutionContext import scala.concurrent.duration.{FiniteDuration, TimeUnit} @@ -48,10 +50,10 @@ trait InterpreterSpec { type Activity = (Long, Int, Option[Long]) case class StatisticState( - activity: List[Activity], - lastDay: List[Long], - lastWeek: List[Long], - lastMonth: List[Long] + activity: List[Activity], + lastDay: List[Long], + lastWeek: List[Long], + lastMonth: List[Long] ) { self => def addActivity(a: Activity): StatisticState = self.copy(activity = activity :+ a) def addLastDay(chatId: Long): StatisticState = self.copy(lastDay = lastDay :+ chatId) @@ -68,10 +70,10 @@ trait InterpreterSpec { } case class TelegramState( - send: List[TSendMessage], - answer: List[TCallbackAnswer], - edit: List[TEditMessage], - me: Int + send: List[TSendMessage], + answer: List[TCallbackAnswer], + edit: List[TEditMessage], + me: Int ) { self => def addSend(m: TSendMessage): TelegramState = self.copy(send = send :+ m) def addAnswer(a: TCallbackAnswer): TelegramState = self.copy(answer = answer :+ a) @@ -85,4 +87,27 @@ trait InterpreterSpec { def editMessageText(message: TEditMessage): IO[Unit] = state.update(_ addEdit message) def getMe: IO[TUser] = state.update(_.addMe).as(TUser(1, isBot = true, "tomodoro", none, none)) } + + case class RepositoryState(logs: List[ActivityLog]) { self => + def addLog(log: ActivityLog): RepositoryState = self.copy(logs = logs :+ log) + } + + class RepositoryIO(state: Ref[IO, RepositoryState]) extends Repository[IO] { + def findLogs(chatId: Long, offset: Long, limit: Long): IO[List[Repository.ActivityLog]] = + state.get.map { s => + s.logs + .filter(log => log.chatId == chatId) + .sorted(Ordering.by((l: ActivityLog) => l.time).reverse) + } + + def addLog(log: Repository.ActivityLog): IO[Unit] = + state.update(_ addLog log) + + def countCompleted(chatId: Long, from: OffsetDateTime, to: OffsetDateTime): IO[Long] = + state.get.map { s => + s.logs + .count(log => log.chatId == chatId && log.time.isAfter(from) && log.time.isBefore(to)) + .toLong + } + } } diff --git a/src/test/scala/org/chepiov/tomodoro/interpreters/StatisticInterpreterSpec.scala b/src/test/scala/org/chepiov/tomodoro/interpreters/StatisticInterpreterSpec.scala new file mode 100644 index 0000000..13e0b9e --- /dev/null +++ b/src/test/scala/org/chepiov/tomodoro/interpreters/StatisticInterpreterSpec.scala @@ -0,0 +1,68 @@ +package org.chepiov.tomodoro.interpreters + +import java.time.OffsetDateTime + +import cats.effect.IO +import cats.effect.concurrent.Ref +import cats.syntax.option._ +import org.chepiov.tomodoro.algebras.Repository.ActivityDescriptor._ +import org.chepiov.tomodoro.algebras.Repository.ActivityLog +import org.chepiov.tomodoro.algebras.Statistic +import org.chepiov.tomodoro.programs.UserMessages._ +import org.scalatest.{Matchers, WordSpecLike} + +@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements")) +class StatisticInterpreterSpec extends WordSpecLike with Matchers with InterpreterSpec { + + private def create(): IO[(Ref[IO, TelegramState], Ref[IO, RepositoryState], Statistic[IO])] = + for { + telegramState <- Ref.of[IO, TelegramState](TelegramState(List(), List(), List(), 0)) + telegram = new TelegramIO(telegramState) + repositoryState <- Ref.of[IO, RepositoryState](RepositoryState(List())) + repository = new RepositoryIO(repositoryState) + statistic <- StatisticInterpreter[IO](telegram, repository) + } yield (telegramState, repositoryState, statistic) + + "Statistic" should { + "send activities correctly" in { + val program = for { + (ts, rs, statistic) <- create() + logs = ActivityLog(1L, OffsetDateTime.now(), CycleReset, "test") :: Nil + _ <- rs.set(RepositoryState(logs)) + _ <- statistic.sendActivity(1L, 0, none) + _ <- statistic.sendActivity(1L, 0, 1L.some) + TelegramState(send, _, edit, _) <- ts.get + } yield { + send shouldBe List(logsMsg(1L, 0, logs)) + edit shouldBe List(logsEditMsg(1L, 1L, 0, logs)) + } + program.unsafeRunSync() + } + } + + it should { + "send completed count correctly" in { + val program = for { + (ts, rs, statistic) <- create() + now = OffsetDateTime.now() + logs = List( + ActivityLog(1L, now, CycleReset, "today"), + ActivityLog(1L, now.minusDays(2), CycleReset, "lastWeek"), + ActivityLog(1L, now.minusDays(8), CycleReset, "lastMonth") + ) + _ <- rs.set(RepositoryState(logs)) + _ <- statistic.sendCompletedLastDay(1L) + _ <- statistic.sendCompletedLastWeek(1L) + _ <- statistic.sendCompletedLastMonth(1L) + TelegramState(send, _, _, _) <- ts.get + } yield { + send shouldBe List( + completedLastDayMsg(1L, 1), + completedLastWeekMsg(1L, 2), + completedLastMonthMsg(1L, 3) + ) + } + program.unsafeRunSync() + } + } +}