forked from ScalaMock/ScalaMock
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathZIOUserAuthServiceSpec.scala
114 lines (90 loc) · 3.07 KB
/
ZIOUserAuthServiceSpec.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package tests
import org.scalamock.stubs.{Stub, ZIOStubs}
import zio.*
import zio.test.*
enum UserStatus:
case Normal, Blocked
enum FailedAuthResult:
case UserNotFound, UserNotAllowed, WrongPassword
case class User(id: Long, status: UserStatus)
trait UserService:
def findUser(userId: Long): UIO[Option[User]]
trait PasswordService:
def checkPassword(id: Long, password: String): UIO[Boolean]
class UserAuthService(
userService: UserService,
passwordService: PasswordService
):
def authorize(id: Long, password: String): IO[FailedAuthResult, Unit] =
userService.findUser(id).flatMap:
case None =>
ZIO.fail(FailedAuthResult.UserNotFound)
case Some(user) if user.status == UserStatus.Blocked =>
ZIO.fail(FailedAuthResult.UserNotAllowed)
case Some(user) =>
passwordService.checkPassword(id, password)
.filterOrFail(identity)(FailedAuthResult.WrongPassword)
.unit
object ZIOUserAuthServiceSpec extends ZIOSpecDefault, ZIOStubs:
val unknownUserId = 0
val user = User(1, UserStatus.Normal)
val blockedUser = User(2, UserStatus.Blocked)
val validPassword = "valid"
val invalidPassword = "invalid"
case class Verify(
passwordCheckedTimes: Option[Int]
)
val spec =
suite("UserAuthService")(
testCase(
description = "error if user not found",
id = unknownUserId,
password = validPassword,
expectedResult = Exit.fail(FailedAuthResult.UserNotFound),
verify = Verify(passwordCheckedTimes = Some(0))
),
testCase(
description = "error if user is blocked",
id = blockedUser.id,
password = validPassword,
expectedResult = Exit.fail(FailedAuthResult.UserNotAllowed),
verify = Verify(passwordCheckedTimes = Some(0))
),
testCase(
description = "error if password is invalid",
id = user.id,
password = invalidPassword,
expectedResult = Exit.fail(FailedAuthResult.WrongPassword),
verify = Verify(passwordCheckedTimes = Some(1))
),
testCase(
description = "password valid",
id = user.id,
password = validPassword,
expectedResult = Exit.unit,
verify = Verify(passwordCheckedTimes = Some(1))
)
)
def testCase(
description: String,
id: Long,
password: String,
expectedResult: Exit[FailedAuthResult, Unit],
verify: Verify
) = test(description) {
val userService = stub[UserService]
val passwordService = stub[PasswordService]
val userAuthService = UserAuthService(userService, passwordService)
for
_ <- userService.findUser.returnsZIO:
case user.id => ZIO.some(user)
case blockedUser.id => ZIO.some(blockedUser)
case _ => ZIO.none
_ <- passwordService.checkPassword.returnsZIO:
case (_, password) => ZIO.succeed(password == validPassword)
result <- userAuthService.authorize(id, password).exit
yield assertTrue(
result == expectedResult,
verify.passwordCheckedTimes.contains(passwordService.checkPassword.times)
)
}