using Infrastructure.Authentication; namespace Application.Tests; [TestClass] public sealed class SocialAuthProviderParserTests { [TestMethod] public void Naver_ParseUserInfo_MapsFields_EmailAlwaysUnverified() { // 네이버 프로필 표준 응답 — email 은 연락처 이메일이라 항상 EmailVerified=false 로 매핑되어야 한다 (d5 §③) const string json = """ {"resultcode":"00","message":"success","response":{"id":"32742776","nickname":"개미","profile_image":"https://ssl.pstatic.net/img.png","email":"ant@example.com","name":"홍길동"}} """; var info = NaverAuthProvider.ParseUserInfo(json); Assert.IsNotNull(info); Assert.AreEqual("32742776", info.ProviderUserKey); Assert.AreEqual("ant@example.com", info.Email); Assert.IsFalse(info.EmailVerified, "네이버 이메일은 검증 플래그가 없어 항상 미검증 취급한다"); Assert.AreEqual("개미", info.Nickname); Assert.AreEqual("https://ssl.pstatic.net/img.png", info.ProfileImageUrl); // resultcode 00 외에는 실패 Assert.IsNull(NaverAuthProvider.ParseUserInfo("""{"resultcode":"024","message":"Authentication failed"}""")); } [TestMethod] public void Naver_ParseTokens_StringExpiresIn_And_ErrorBody() { // 네이버 토큰 응답은 expires_in 이 문자열("3600")로 온다 + 오류가 200 으로 내려오는 케이스(error 필드)도 걸러야 한다 const string json = """ {"access_token":"AAAAQosjWDJieBiQZc3to9YQp6HDLNzYyBYyO8","refresh_token":"c8ceMEJisO4Se7uGisHoX0f5JEii7JnipglQipkOn5Zp3tyP7dHQoP0zNKHUq2gY","token_type":"bearer","expires_in":"3600"} """; var before = DateTime.UtcNow; var tokens = NaverAuthProvider.ParseTokens(json); Assert.IsNotNull(tokens); Assert.AreEqual("AAAAQosjWDJieBiQZc3to9YQp6HDLNzYyBYyO8", tokens.AccessToken); Assert.IsNotNull(tokens.RefreshToken); Assert.IsTrue(tokens.ExpiresAt > before.AddSeconds(3000) && tokens.ExpiresAt <= before.AddSeconds(3600), "문자열 expires_in(3600)이 파싱되어야 한다"); Assert.IsNull(NaverAuthProvider.ParseTokens("""{"error":"invalid_request","error_description":"no valid data in session"}"""), "error 필드가 있으면 실패로 처리한다"); } [TestMethod] public void Kakao_ParseUserInfo_VerifiedEmail_MapsFields() { // 카카오 v2/user/me — id 는 int64, 검증된 이메일은 EmailVerified=true 로 매핑 const string json = """ {"id":123456789,"connected_at":"2026-07-03T01:00:00Z","kakao_account":{"profile_nickname_needs_agreement":false,"profile":{"nickname":"개미왕","thumbnail_image_url":"https://k.kakaocdn.net/thumb.jpg","profile_image_url":"https://k.kakaocdn.net/profile.jpg"},"has_email":true,"email_needs_agreement":false,"is_email_valid":true,"is_email_verified":true,"email":"ant@kakao.com"}} """; var info = KakaoAuthProvider.ParseUserInfo(json); Assert.IsNotNull(info); Assert.AreEqual("123456789", info.ProviderUserKey, "int64 id 는 문자열화하여 ProviderUserKey 로 쓴다"); Assert.AreEqual("ant@kakao.com", info.Email); Assert.IsTrue(info.EmailVerified); Assert.AreEqual("개미왕", info.Nickname); Assert.AreEqual("https://k.kakaocdn.net/profile.jpg", info.ProfileImageUrl); } [TestMethod] public void Kakao_ParseUserInfo_EmailNotAgreed_ReturnsNullEmail() { // 카카오 account_email 은 선택동의 — 미동의 시 email 부재 → Email null (핸들러가 Auth.EmailRequired 로 분기) const string json = """ {"id":987654321,"kakao_account":{"profile":{"nickname":"미동의개미"},"has_email":true,"email_needs_agreement":true}} """; var info = KakaoAuthProvider.ParseUserInfo(json); Assert.IsNotNull(info); Assert.AreEqual("987654321", info.ProviderUserKey); Assert.IsNull(info.Email, "이메일 미동의 시 null 이어야 한다"); Assert.IsFalse(info.EmailVerified); Assert.AreEqual("미동의개미", info.Nickname); } }