initial commit

This commit is contained in:
m.zare
2026-04-10 18:25:21 +03:30
commit 77ca6c34a3
263 changed files with 34470 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
package specialist_test
import (
"context"
"errors"
"testing"
"github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
appMock "base/internal/application/mock"
"base/internal/application/specialist"
domainAsset "base/internal/domain/asset"
domainProfile "base/internal/domain/profile"
)
func TestSpecialistService_Overview(t *testing.T) {
ctx := context.Background()
logger := zerolog.Nop()
userID := uuid.New()
profileID := uuid.New()
t.Run("success - returns overview with profile, assets, tasks", func(t *testing.T) {
assetRepo := new(appMock.MockAssetRepository)
profileRepo := new(appMock.MockProfileRepository)
profile := &domainProfile.Profile{
ID: profileID,
Handle: "specialist-user",
UserID: &userID,
Hero: domainProfile.Hero{
FirstName: "Jane",
LastName: "Doe",
ShortDescription: "ML Engineer",
},
About: domainProfile.About{
ProfilePicture: "avatar.jpg",
About: "About me",
},
Skills: []domainProfile.Skill{
{SkillName: "Go", Level: "expert"},
},
Contact: domainProfile.Contact{
Email: "jane@example.com",
SocialLinks: []domainProfile.SocialLink{{LinkType: "github", Link: "https://github.com/jane"}},
},
PageSetting: domainProfile.PageSetting{VisibilityLevel: "public"},
}
asset := &domainAsset.Asset{
ID: uuid.New(),
ProfileID: profileID,
Status: domainAsset.StatusPublished,
AssetCategoryID: uuid.New(),
Title: "My Project",
Description: "A cool project",
AssetArtifacts: []domainAsset.Artifact{{Type: "image", DownloadURL: "cover.png", Price: 0}},
}
otherProfile := &domainProfile.Profile{
ID: uuid.New(),
Handle: "other-user",
Hero: domainProfile.Hero{FirstName: "Other", LastName: "User"},
PageSetting: domainProfile.PageSetting{VisibilityLevel: "public"},
}
profileRepo.On("FindByUserID", ctx, userID).Return(profile, nil)
assetRepo.On("FindByProfileID", ctx, profileID).Return([]*domainAsset.Asset{asset}, nil)
profileRepo.On("FindAll", ctx, mock.MatchedBy(func(arg interface{}) bool {
f, ok := arg.(domainProfile.Filter)
if !ok {
return false
}
return f.Page == 1 && f.PageSize == 6 && f.SortedBy == "created_at" && !f.Ascending
})).Return([]*domainProfile.Profile{otherProfile}, 26, nil)
assetRepo.On("Count", ctx).Return(42, nil)
svc := specialist.New(specialist.Param{
Logger: logger,
ProfileRepo: profileRepo,
AssetRepo: assetRepo,
})
resp, err := svc.Overview(ctx, userID)
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, "", resp.Message)
assert.Len(t, resp.Data.Assets, 1)
assert.Equal(t, "My Project", resp.Data.Assets[0].Title)
assert.Len(t, resp.Data.RecentlyJoined, 1)
assert.Equal(t, "other-user", resp.Data.RecentlyJoined[0].ProfileHandle)
assert.Equal(t, 42, resp.Data.Analytics.TotalAssets)
assert.Equal(t, 26, resp.Data.Analytics.TotalProfiles)
require.NotNil(t, resp.Data.Profile)
assert.Equal(t, "specialist-user", resp.Data.Profile.Handle)
assert.Len(t, resp.Data.Skills, 1)
assert.Equal(t, "Go", resp.Data.Skills[0].SkillName)
// All sections complete -> 100% or high completion
assert.False(t, resp.Data.Tasks.ProfileAction)
assert.False(t, resp.Data.Tasks.AboutAction)
assert.False(t, resp.Data.Tasks.PublishAction)
assert.False(t, resp.Data.Tasks.WorksAction)
assert.False(t, resp.Data.Tasks.SkillsAction)
assert.False(t, resp.Data.Tasks.SocialAction)
assert.Equal(t, 100, resp.Data.CompletionPercent)
assetRepo.AssertExpectations(t)
profileRepo.AssertExpectations(t)
})
t.Run("profile not found returns ErrProfileNotFound", func(t *testing.T) {
assetRepo := new(appMock.MockAssetRepository)
profileRepo := new(appMock.MockProfileRepository)
profileRepo.On("FindByUserID", ctx, userID).Return(nil, domainProfile.ErrProfileNotFound)
svc := specialist.New(specialist.Param{
Logger: logger,
ProfileRepo: profileRepo,
AssetRepo: assetRepo,
})
resp, err := svc.Overview(ctx, userID)
assert.Error(t, err)
assert.True(t, errors.Is(err, domainProfile.ErrProfileNotFound))
assert.Nil(t, resp)
profileRepo.AssertExpectations(t)
})
t.Run("incomplete profile computes tasks and completion percent", func(t *testing.T) {
assetRepo := new(appMock.MockAssetRepository)
profileRepo := new(appMock.MockProfileRepository)
profile := &domainProfile.Profile{
ID: profileID,
Handle: "incomplete",
UserID: &userID,
Hero: domainProfile.Hero{FirstName: "A"}, // missing LastName, ShortDescription
About: domainProfile.About{}, // missing picture, about
Skills: []domainProfile.Skill{},
PageSetting: domainProfile.PageSetting{VisibilityLevel: "private"},
}
profileRepo.On("FindByUserID", ctx, userID).Return(profile, nil)
assetRepo.On("FindByProfileID", ctx, profileID).Return([]*domainAsset.Asset{}, nil)
profileRepo.On("FindAll", ctx, mock.Anything).Return([]*domainProfile.Profile{}, 0, nil)
assetRepo.On("Count", ctx).Return(0, nil)
svc := specialist.New(specialist.Param{
Logger: logger,
ProfileRepo: profileRepo,
AssetRepo: assetRepo,
})
resp, err := svc.Overview(ctx, userID)
require.NoError(t, err)
require.NotNil(t, resp)
assert.True(t, resp.Data.Tasks.ProfileAction)
assert.True(t, resp.Data.Tasks.AboutAction)
assert.True(t, resp.Data.Tasks.PublishAction)
assert.True(t, resp.Data.Tasks.WorksAction)
assert.True(t, resp.Data.Tasks.SkillsAction)
assert.True(t, resp.Data.Tasks.SocialAction)
assert.Equal(t, 0, resp.Data.CompletionPercent)
})
}