430 lines
18 KiB
HTML
430 lines
18 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
<title>unit: Go Coverage Report</title>
|
||
<style>
|
||
body {
|
||
background: black;
|
||
color: rgb(80, 80, 80);
|
||
}
|
||
body, pre, #legend span {
|
||
font-family: Menlo, monospace;
|
||
font-weight: bold;
|
||
}
|
||
#topbar {
|
||
background: black;
|
||
position: fixed;
|
||
top: 0; left: 0; right: 0;
|
||
height: 42px;
|
||
border-bottom: 1px solid rgb(80, 80, 80);
|
||
}
|
||
#content {
|
||
margin-top: 50px;
|
||
}
|
||
#nav, #legend {
|
||
float: left;
|
||
margin-left: 10px;
|
||
}
|
||
#legend {
|
||
margin-top: 12px;
|
||
}
|
||
#nav {
|
||
margin-top: 10px;
|
||
}
|
||
#legend span {
|
||
margin: 0 5px;
|
||
}
|
||
.cov0 { color: rgb(192, 0, 0) }
|
||
.cov1 { color: rgb(128, 128, 128) }
|
||
.cov2 { color: rgb(116, 140, 131) }
|
||
.cov3 { color: rgb(104, 152, 134) }
|
||
.cov4 { color: rgb(92, 164, 137) }
|
||
.cov5 { color: rgb(80, 176, 140) }
|
||
.cov6 { color: rgb(68, 188, 143) }
|
||
.cov7 { color: rgb(56, 200, 146) }
|
||
.cov8 { color: rgb(44, 212, 149) }
|
||
.cov9 { color: rgb(32, 224, 152) }
|
||
.cov10 { color: rgb(20, 236, 155) }
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="topbar">
|
||
<div id="nav">
|
||
<select id="files">
|
||
|
||
<option value="file0">wish-list-api/tests/unit/mock_auth.go (22.5%)</option>
|
||
|
||
<option value="file1">wish-list-api/tests/unit/mock_repository.go (56.5%)</option>
|
||
|
||
</select>
|
||
</div>
|
||
<div id="legend">
|
||
<span>not tracked</span>
|
||
|
||
<span class="cov0">not covered</span>
|
||
<span class="cov8">covered</span>
|
||
|
||
</div>
|
||
</div>
|
||
<div id="content">
|
||
|
||
<pre class="file" id="file0" style="display: none">package unit
|
||
|
||
import (
|
||
"errors"
|
||
"time"
|
||
"wish-list-api/pkg/auth"
|
||
"wish-list-api/pkg/entities"
|
||
|
||
"github.com/golang-jwt/jwt/v5"
|
||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
)
|
||
|
||
// MockAuthService реализует интерфейс auth.Service
|
||
type MockAuthService struct {
|
||
users map[primitive.ObjectID]*entities.User
|
||
// Токен -> ID пользователя
|
||
tokens map[string]primitive.ObjectID
|
||
}
|
||
|
||
// NewMockAuthService создает новый mock сервис аутентификации
|
||
func NewMockAuthService() auth.Service <span class="cov8" title="1">{
|
||
return &MockAuthService{
|
||
users: make(map[primitive.ObjectID]*entities.User),
|
||
tokens: make(map[string]primitive.ObjectID),
|
||
}
|
||
}</span>
|
||
|
||
// AddMockUser добавляет мок-пользователя в сервис
|
||
func (m *MockAuthService) AddMockUser(user *entities.User, token string) <span class="cov8" title="1">{
|
||
m.users[user.ID] = user
|
||
m.tokens[token] = user.ID
|
||
}</span>
|
||
|
||
// Login реализация для теста
|
||
func (m *MockAuthService) Login(credentials *entities.LoginRequest) (*entities.TokenPair, error) <span class="cov0" title="0">{
|
||
for _, user := range m.users </span><span class="cov0" title="0">{
|
||
if user.Email == credentials.Email && m.ComparePasswords(user.Password, credentials.Password) </span><span class="cov0" title="0">{
|
||
token := "mock-token-for-" + user.ID.Hex()
|
||
m.tokens[token] = user.ID
|
||
return &entities.TokenPair{
|
||
AccessToken: token,
|
||
RefreshToken: "refresh-" + token,
|
||
}, nil
|
||
}</span>
|
||
}
|
||
<span class="cov0" title="0">return nil, errors.New("invalid credentials")</span>
|
||
}
|
||
|
||
// Register реализация для теста
|
||
func (m *MockAuthService) Register(userData *entities.RegisterRequest) (*entities.User, error) <span class="cov0" title="0">{
|
||
// Проверяем, что email не занят
|
||
for _, existingUser := range m.users </span><span class="cov0" title="0">{
|
||
if existingUser.Email == userData.Email </span><span class="cov0" title="0">{
|
||
return nil, errors.New("email already exists")
|
||
}</span>
|
||
}
|
||
|
||
// Создаем нового пользователя
|
||
<span class="cov0" title="0">hashedPassword, _ := m.HashPassword(userData.Password)
|
||
user := &entities.User{
|
||
ID: primitive.NewObjectID(),
|
||
Email: userData.Email,
|
||
Password: hashedPassword,
|
||
CreatedAt: time.Now(),
|
||
UpdatedAt: time.Now(),
|
||
}
|
||
|
||
// Сохраняем пользователя
|
||
m.users[user.ID] = user
|
||
|
||
return user, nil</span>
|
||
}
|
||
|
||
// RefreshToken реализация для теста
|
||
func (m *MockAuthService) RefreshToken(refreshToken string) (*entities.TokenPair, error) <span class="cov0" title="0">{
|
||
// Предполагаем, что refresh token имеет вид "refresh-<access-token>"
|
||
if len(refreshToken) < 8 </span><span class="cov0" title="0">{
|
||
return nil, errors.New("invalid refresh token")
|
||
}</span>
|
||
|
||
<span class="cov0" title="0">accessToken := refreshToken[8:] // Получаем access token из refresh token
|
||
userID, ok := m.tokens[accessToken]
|
||
if !ok </span><span class="cov0" title="0">{
|
||
return nil, errors.New("invalid refresh token")
|
||
}</span>
|
||
|
||
<span class="cov0" title="0">newToken := "mock-token-for-" + userID.Hex() + "-refreshed"
|
||
m.tokens[newToken] = userID
|
||
|
||
return &entities.TokenPair{
|
||
AccessToken: newToken,
|
||
RefreshToken: "refresh-" + newToken,
|
||
}, nil</span>
|
||
}
|
||
|
||
// ValidateToken реализация для теста
|
||
func (m *MockAuthService) ValidateToken(tokenString string) (*jwt.Token, error) <span class="cov0" title="0">{
|
||
// Проверяем, имеет ли токен префикс "Bearer "
|
||
if len(tokenString) > 7 && tokenString[:7] == "Bearer " </span><span class="cov0" title="0">{
|
||
tokenString = tokenString[7:]
|
||
}</span>
|
||
|
||
<span class="cov0" title="0">userID, ok := m.tokens[tokenString]
|
||
if !ok </span><span class="cov0" title="0">{
|
||
return nil, errors.New("invalid token")
|
||
}</span>
|
||
|
||
// Создаем mock JWT token
|
||
<span class="cov0" title="0">token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||
"user_id": userID.Hex(),
|
||
"exp": time.Now().Add(time.Hour).Unix(),
|
||
})
|
||
|
||
return token, nil</span>
|
||
}
|
||
|
||
// GetUserIDFromToken реализация для теста
|
||
func (m *MockAuthService) GetUserIDFromToken(tokenString string) (string, error) <span class="cov8" title="1">{
|
||
// Проверяем, имеет ли токен префикс "Bearer "
|
||
if len(tokenString) > 7 && tokenString[:7] == "Bearer " </span><span class="cov8" title="1">{
|
||
tokenString = tokenString[7:]
|
||
}</span>
|
||
|
||
<span class="cov8" title="1">userID, ok := m.tokens[tokenString]
|
||
if !ok </span><span class="cov8" title="1">{
|
||
return "", errors.New("invalid token")
|
||
}</span>
|
||
<span class="cov8" title="1">return userID.Hex(), nil</span>
|
||
}
|
||
|
||
// HashPassword реализация для теста
|
||
func (m *MockAuthService) HashPassword(password string) (string, error) <span class="cov0" title="0">{
|
||
// Просто возвращаем пароль с префиксом для имитации хеширования
|
||
return "hashed_" + password, nil
|
||
}</span>
|
||
|
||
// ComparePasswords реализация для теста
|
||
func (m *MockAuthService) ComparePasswords(hashedPassword string, plainPassword string) bool <span class="cov0" title="0">{
|
||
// Проверяем, соответствует ли "хешированный" пароль нашей простой схеме
|
||
return hashedPassword == "hashed_"+plainPassword
|
||
}</span>
|
||
</pre>
|
||
|
||
<pre class="file" id="file1" style="display: none">package unit
|
||
|
||
import (
|
||
"errors"
|
||
"time"
|
||
|
||
"wish-list-api/api/presenter"
|
||
"wish-list-api/pkg/entities"
|
||
wishlist "wish-list-api/pkg/wish-list"
|
||
|
||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
)
|
||
|
||
// MockWishListRepository реализует интерфейс Repository для тестирования
|
||
type MockWishListRepository struct {
|
||
wishLists map[string]*entities.WishList
|
||
wishListItems map[string]*entities.WishListItem
|
||
}
|
||
|
||
// NewMockWishListRepository создает новый экземпляр мок-репозитория
|
||
func NewMockWishListRepository() wishlist.Repository <span class="cov8" title="1">{
|
||
return &MockWishListRepository{
|
||
wishLists: make(map[string]*entities.WishList),
|
||
wishListItems: make(map[string]*entities.WishListItem),
|
||
}
|
||
}</span>
|
||
|
||
// CreateWishList реализует создание списка желаний
|
||
func (r *MockWishListRepository) CreateWishList(wishList *entities.WishList) (*entities.WishList, error) <span class="cov8" title="1">{
|
||
if wishList.ID == "" </span><span class="cov8" title="1">{
|
||
wishList.ID = "mock-id-" + time.Now().String()
|
||
}</span>
|
||
<span class="cov8" title="1">wishList.CreatedAt = time.Now()
|
||
wishList.UpdatedAt = time.Now()
|
||
r.wishLists[wishList.ID] = wishList
|
||
return wishList, nil</span>
|
||
}
|
||
|
||
// ReadWishList реализует чтение списка желаний по ID
|
||
func (r *MockWishListRepository) ReadWishList(ID string) (*entities.WishList, error) <span class="cov8" title="1">{
|
||
if wishList, ok := r.wishLists[ID]; ok </span><span class="cov8" title="1">{
|
||
return wishList, nil
|
||
}</span>
|
||
<span class="cov8" title="1">return nil, errors.New("wishlist not found")</span>
|
||
}
|
||
|
||
// ReadAllWishLists реализует чтение всех списков желаний пользователя
|
||
func (r *MockWishListRepository) ReadAllWishLists(userID string) (*[]presenter.WishList, error) <span class="cov0" title="0">{
|
||
var result []presenter.WishList
|
||
for _, wl := range r.wishLists </span><span class="cov0" title="0">{
|
||
if wl.UserID == userID </span><span class="cov0" title="0">{
|
||
objID, _ := primitive.ObjectIDFromHex(wl.ID)
|
||
result = append(result, presenter.WishList{
|
||
ID: objID,
|
||
Title: wl.Title,
|
||
UserID: wl.UserID,
|
||
Description: wl.Description,
|
||
IsPublic: wl.IsPublic,
|
||
PhotoURL: wl.PhotoURL,
|
||
CreatedAt: wl.CreatedAt,
|
||
UpdatedAt: wl.UpdatedAt,
|
||
})
|
||
}</span>
|
||
}
|
||
<span class="cov0" title="0">return &result, nil</span>
|
||
}
|
||
|
||
// ReadPublicWishLists реализует чтение всех публичных списков желаний
|
||
func (r *MockWishListRepository) ReadPublicWishLists() (*[]presenter.WishList, error) <span class="cov0" title="0">{
|
||
var result []presenter.WishList
|
||
for _, wl := range r.wishLists </span><span class="cov0" title="0">{
|
||
if wl.IsPublic </span><span class="cov0" title="0">{
|
||
objID, _ := primitive.ObjectIDFromHex(wl.ID)
|
||
result = append(result, presenter.WishList{
|
||
ID: objID,
|
||
Title: wl.Title,
|
||
UserID: wl.UserID,
|
||
Description: wl.Description,
|
||
IsPublic: wl.IsPublic,
|
||
PhotoURL: wl.PhotoURL,
|
||
CreatedAt: wl.CreatedAt,
|
||
UpdatedAt: wl.UpdatedAt,
|
||
})
|
||
}</span>
|
||
}
|
||
<span class="cov0" title="0">return &result, nil</span>
|
||
}
|
||
|
||
// UpdateWishList реализует обновление списка желаний
|
||
func (r *MockWishListRepository) UpdateWishList(wishList *entities.WishList) (*entities.WishList, error) <span class="cov8" title="1">{
|
||
if _, ok := r.wishLists[wishList.ID]; !ok </span><span class="cov8" title="1">{
|
||
return nil, errors.New("wishlist not found")
|
||
}</span>
|
||
<span class="cov8" title="1">wishList.UpdatedAt = time.Now()
|
||
r.wishLists[wishList.ID] = wishList
|
||
return wishList, nil</span>
|
||
}
|
||
|
||
// DeleteWishList реализует удаление списка желаний
|
||
func (r *MockWishListRepository) DeleteWishList(ID string) error <span class="cov8" title="1">{
|
||
if _, ok := r.wishLists[ID]; !ok </span><span class="cov8" title="1">{
|
||
return errors.New("wishlist not found")
|
||
}</span>
|
||
<span class="cov8" title="1">delete(r.wishLists, ID)
|
||
|
||
// Удаляем все элементы, связанные с этим списком
|
||
for id, item := range r.wishListItems </span><span class="cov0" title="0">{
|
||
if item.WishListID == ID </span><span class="cov0" title="0">{
|
||
delete(r.wishListItems, id)
|
||
}</span>
|
||
}
|
||
<span class="cov8" title="1">return nil</span>
|
||
}
|
||
|
||
// CreateWishListItem реализует создание элемента списка желаний
|
||
func (r *MockWishListRepository) CreateWishListItem(item *entities.WishListItem) (*entities.WishListItem, error) <span class="cov8" title="1">{
|
||
if _, ok := r.wishLists[item.WishListID]; !ok </span><span class="cov8" title="1">{
|
||
return nil, errors.New("wishlist not found")
|
||
}</span>
|
||
|
||
<span class="cov8" title="1">if item.ID == "" </span><span class="cov8" title="1">{
|
||
item.ID = "mock-item-id-" + time.Now().String()
|
||
}</span>
|
||
<span class="cov8" title="1">item.CreatedAt = time.Now()
|
||
item.UpdatedAt = time.Now()
|
||
r.wishListItems[item.ID] = item
|
||
return item, nil</span>
|
||
}
|
||
|
||
// ReadWishListItem реализует чтение элемента списка желаний по ID
|
||
func (r *MockWishListRepository) ReadWishListItem(ID string) (*entities.WishListItem, error) <span class="cov0" title="0">{
|
||
if item, ok := r.wishListItems[ID]; ok </span><span class="cov0" title="0">{
|
||
return item, nil
|
||
}</span>
|
||
<span class="cov0" title="0">return nil, errors.New("wishlist item not found")</span>
|
||
}
|
||
|
||
// ReadAllWishListItems реализует чтение всех элементов списка желаний
|
||
func (r *MockWishListRepository) ReadAllWishListItems(wishListID string) (*[]presenter.WishListItem, error) <span class="cov8" title="1">{
|
||
if _, ok := r.wishLists[wishListID]; !ok </span><span class="cov0" title="0">{
|
||
return nil, errors.New("wishlist not found")
|
||
}</span>
|
||
|
||
<span class="cov8" title="1">var result []presenter.WishListItem
|
||
for _, item := range r.wishListItems </span><span class="cov8" title="1">{
|
||
if item.WishListID == wishListID </span><span class="cov8" title="1">{
|
||
objID, _ := primitive.ObjectIDFromHex(item.ID)
|
||
result = append(result, presenter.WishListItem{
|
||
ID: objID,
|
||
Title: item.Title,
|
||
URL: item.URL,
|
||
Cost: item.Cost,
|
||
WishListID: item.WishListID,
|
||
Description: item.Description,
|
||
PhotoURL: item.PhotoURL,
|
||
CreatedAt: item.CreatedAt,
|
||
UpdatedAt: item.UpdatedAt,
|
||
})
|
||
}</span>
|
||
}
|
||
<span class="cov8" title="1">return &result, nil</span>
|
||
}
|
||
|
||
// UpdateWishListItem реализует обновление элемента списка желаний
|
||
func (r *MockWishListRepository) UpdateWishListItem(item *entities.WishListItem) (*entities.WishListItem, error) <span class="cov0" title="0">{
|
||
if _, ok := r.wishListItems[item.ID]; !ok </span><span class="cov0" title="0">{
|
||
return nil, errors.New("wishlist item not found")
|
||
}</span>
|
||
<span class="cov0" title="0">item.UpdatedAt = time.Now()
|
||
r.wishListItems[item.ID] = item
|
||
return item, nil</span>
|
||
}
|
||
|
||
// DeleteWishListItem реализует удаление элемента списка желаний
|
||
func (r *MockWishListRepository) DeleteWishListItem(ID string) error <span class="cov0" title="0">{
|
||
if _, ok := r.wishListItems[ID]; !ok </span><span class="cov0" title="0">{
|
||
return errors.New("wishlist item not found")
|
||
}</span>
|
||
<span class="cov0" title="0">delete(r.wishListItems, ID)
|
||
return nil</span>
|
||
}
|
||
</pre>
|
||
|
||
</div>
|
||
</body>
|
||
<script>
|
||
(function() {
|
||
var files = document.getElementById('files');
|
||
var visible;
|
||
files.addEventListener('change', onChange, false);
|
||
function select(part) {
|
||
if (visible)
|
||
visible.style.display = 'none';
|
||
visible = document.getElementById(part);
|
||
if (!visible)
|
||
return;
|
||
files.value = part;
|
||
visible.style.display = 'block';
|
||
location.hash = part;
|
||
}
|
||
function onChange() {
|
||
select(files.value);
|
||
window.scrollTo(0, 0);
|
||
}
|
||
if (location.hash != "") {
|
||
select(location.hash.substr(1));
|
||
}
|
||
if (!visible) {
|
||
select("file0");
|
||
}
|
||
})();
|
||
</script>
|
||
</html>
|