mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-10 18:10:49 +09:00
GO-3964 Add tests on service
This commit is contained in:
parent
bdfdbdb35a
commit
2c7139d6aa
4 changed files with 709 additions and 5 deletions
|
@ -1,12 +1,17 @@
|
|||
package details
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/state"
|
||||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
|
||||
|
@ -15,8 +20,6 @@ import (
|
|||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
)
|
||||
|
||||
const spaceId = "spaceId"
|
||||
|
||||
func relationObject(key domain.RelationKey, format model.RelationFormat) objectstore.TestObject {
|
||||
return objectstore.TestObject{
|
||||
bundle.RelationKeyId: pbtypes.String(key.URL()),
|
||||
|
@ -117,3 +120,91 @@ func TestService_ListRelationsWithValue(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_ObjectTypeAddRelations(t *testing.T) {
|
||||
t.Run("add recommended relations", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(bundle.TypeKeyTask.URL())
|
||||
sb.SetSpace(fx.space)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, bundle.TypeKeyTask.URL(), objectId)
|
||||
return sb, nil
|
||||
})
|
||||
fx.space.EXPECT().GetRelationIdByKey(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, key domain.RelationKey) (string, error) {
|
||||
return key.URL(), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.ObjectTypeAddRelations(nil, bundle.TypeKeyTask.URL(), []domain.RelationKey{
|
||||
bundle.RelationKeyAssignee, bundle.RelationKeyDone,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{bundle.RelationKeyAssignee.URL(), bundle.RelationKeyDone.URL()},
|
||||
pbtypes.GetStringList(sb.Details(), bundle.RelationKeyRecommendedRelations.String()))
|
||||
})
|
||||
|
||||
t.Run("editing of bundled types is prohibited", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
|
||||
// when
|
||||
err := fx.ObjectTypeAddRelations(nil, bundle.TypeKeyTask.BundledURL(), []domain.RelationKey{
|
||||
bundle.RelationKeyAssignee, bundle.RelationKeyDone,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, ErrBundledTypeIsReadonly, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ObjectTypeRemoveRelations(t *testing.T) {
|
||||
t.Run("remove recommended relations", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(bundle.TypeKeyTask.URL())
|
||||
sb.SetSpace(fx.space)
|
||||
sb.Doc.(*state.State).SetDetails(&types.Struct{Fields: map[string]*types.Value{
|
||||
bundle.RelationKeyRecommendedRelations.String(): pbtypes.StringList([]string{
|
||||
bundle.RelationKeyAssignee.URL(),
|
||||
bundle.RelationKeyIsFavorite.URL(),
|
||||
bundle.RelationKeyDone.URL(),
|
||||
bundle.RelationKeyLinkedProjects.URL(),
|
||||
}),
|
||||
}})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, bundle.TypeKeyTask.URL(), objectId)
|
||||
return sb, nil
|
||||
})
|
||||
fx.space.EXPECT().GetRelationIdByKey(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, key domain.RelationKey) (string, error) {
|
||||
return key.URL(), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.ObjectTypeRemoveRelations(nil, bundle.TypeKeyTask.URL(), []domain.RelationKey{
|
||||
bundle.RelationKeyAssignee, bundle.RelationKeyDone,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{bundle.RelationKeyIsFavorite.URL(), bundle.RelationKeyLinkedProjects.URL()},
|
||||
pbtypes.GetStringList(sb.Details(), bundle.RelationKeyRecommendedRelations.String()))
|
||||
})
|
||||
|
||||
t.Run("editing of bundled types is prohibited", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
|
||||
// when
|
||||
err := fx.ObjectTypeRemoveRelations(nil, bundle.TypeKeyTask.BundledURL(), []domain.RelationKey{
|
||||
bundle.RelationKeyAssignee, bundle.RelationKeyDone,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, ErrBundledTypeIsReadonly, err)
|
||||
})
|
||||
}
|
567
core/block/details/service_test.go
Normal file
567
core/block/details/service_test.go
Normal file
|
@ -0,0 +1,567 @@
|
|||
package details
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anyproto/anytype-heart/core/block/editor"
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/basic"
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
|
||||
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
|
||||
"github.com/anyproto/anytype-heart/core/block/object/idresolver/mock_idresolver"
|
||||
"github.com/anyproto/anytype-heart/core/block/restriction"
|
||||
"github.com/anyproto/anytype-heart/core/block/restriction/mock_restriction"
|
||||
"github.com/anyproto/anytype-heart/core/block/simple"
|
||||
"github.com/anyproto/anytype-heart/pb"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
|
||||
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/threads"
|
||||
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
|
||||
"github.com/anyproto/anytype-heart/space/mock_space"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
)
|
||||
|
||||
const spaceId = "spaceId"
|
||||
|
||||
type fixture struct {
|
||||
Service
|
||||
resolver *mock_idresolver.MockResolver
|
||||
spaceService *mock_space.MockService
|
||||
store *objectstore.StoreFixture
|
||||
restriction *mock_restriction.MockService
|
||||
space *mock_clientspace.MockSpace
|
||||
}
|
||||
|
||||
func newFixture(t *testing.T) *fixture {
|
||||
resolver := mock_idresolver.NewMockResolver(t)
|
||||
spaceService := mock_space.NewMockService(t)
|
||||
store := objectstore.NewStoreFixture(t)
|
||||
restriction := mock_restriction.NewMockService(t)
|
||||
|
||||
spc := mock_clientspace.NewMockSpace(t)
|
||||
resolver.EXPECT().ResolveSpaceID(mock.Anything).Return(spaceId, nil).Maybe()
|
||||
spaceService.EXPECT().Get(mock.Anything, mock.Anything).Return(spc, nil).Maybe()
|
||||
|
||||
s := &service{
|
||||
resolver: resolver,
|
||||
spaceService: spaceService,
|
||||
store: store,
|
||||
restriction: restriction,
|
||||
}
|
||||
|
||||
return &fixture{
|
||||
s,
|
||||
resolver,
|
||||
spaceService,
|
||||
store,
|
||||
restriction,
|
||||
spc,
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_SetDetailsList(t *testing.T) {
|
||||
details := []*model.Detail{
|
||||
{Key: bundle.RelationKeyAssignee.String(), Value: pbtypes.String("Mark Twain")},
|
||||
{Key: bundle.RelationKeyDone.String(), Value: pbtypes.Bool(true)},
|
||||
{Key: bundle.RelationKeyLinkedProjects.String(), Value: pbtypes.StringList([]string{"important", "urgent"})},
|
||||
}
|
||||
|
||||
t.Run("lastUsed is updated once", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
objects := map[string]*smarttest.SmartTest{
|
||||
"obj1": smarttest.New("obj1"),
|
||||
"obj2": smarttest.New("obj2"),
|
||||
"obj3": smarttest.New("obj3"),
|
||||
}
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
object, ok := objects[objectId]
|
||||
require.True(t, ok)
|
||||
return object, nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetDetailsList(nil, []string{"obj1", "obj2", "obj3"}, details)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, objects["obj1"].Results.LastUsedUpdates, 3)
|
||||
assert.Equal(t, []string{
|
||||
bundle.RelationKeyAssignee.String(),
|
||||
bundle.RelationKeyDone.String(),
|
||||
bundle.RelationKeyLinkedProjects.String(),
|
||||
}, objects["obj1"].Results.LastUsedUpdates)
|
||||
|
||||
// lastUsed should be updated only during the work under 1st object
|
||||
assert.Len(t, objects["obj2"].Results.LastUsedUpdates, 0)
|
||||
assert.Len(t, objects["obj3"].Results.LastUsedUpdates, 0)
|
||||
|
||||
assert.Equal(t, "Mark Twain", pbtypes.GetString(objects["obj1"].NewState().Details(), bundle.RelationKeyAssignee.String()))
|
||||
assert.True(t, pbtypes.GetBool(objects["obj2"].NewState().Details(), bundle.RelationKeyDone.String()))
|
||||
assert.Equal(t, []string{"important", "urgent"}, pbtypes.GetStringList(objects["obj3"].NewState().Details(), bundle.RelationKeyLinkedProjects.String()))
|
||||
})
|
||||
|
||||
t.Run("some updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId != "obj2" {
|
||||
return nil, fmt.Errorf("failed to find object")
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetDetailsList(nil, []string{"obj1", "obj2", "obj3"}, details)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("all updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, _ string) (smartblock.SmartBlock, error) {
|
||||
return nil, fmt.Errorf("failed to find object")
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetDetailsList(nil, []string{"obj1", "obj2", "obj3"}, details)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_ModifyDetailsList(t *testing.T) {
|
||||
ops := []*pb.RpcObjectListModifyDetailValuesRequestOperation{
|
||||
{RelationKey: bundle.RelationKeyName.String(), Set: pbtypes.String("My favorite page")},
|
||||
{RelationKey: bundle.RelationKeyLinks.String(), Add: pbtypes.String("some link")},
|
||||
{RelationKey: bundle.RelationKeyDone.String(), Set: pbtypes.Bool(true)},
|
||||
}
|
||||
|
||||
t.Run("lastUsed is updated once", func(t *testing.T) {
|
||||
fx := newFixture(t)
|
||||
objects := map[string]*smarttest.SmartTest{
|
||||
"obj1": smarttest.New("obj1"),
|
||||
"obj2": smarttest.New("obj2"),
|
||||
"obj3": smarttest.New("obj3"),
|
||||
}
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
object, ok := objects[objectId]
|
||||
require.True(t, ok)
|
||||
return object, nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.ModifyDetailsList(&pb.RpcObjectListModifyDetailValuesRequest{
|
||||
ObjectIds: []string{"obj1", "obj2", "obj3"},
|
||||
Operations: ops,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, objects["obj1"].Results.LastUsedUpdates, 3)
|
||||
|
||||
// lastUsed should be updated only during the work under 1st object
|
||||
assert.Len(t, objects["obj2"].Results.LastUsedUpdates, 0)
|
||||
assert.Len(t, objects["obj3"].Results.LastUsedUpdates, 0)
|
||||
})
|
||||
|
||||
t.Run("some updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId != "obj2" {
|
||||
return nil, fmt.Errorf("failed to find object")
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.ModifyDetailsList(&pb.RpcObjectListModifyDetailValuesRequest{
|
||||
ObjectIds: []string{"obj1", "obj2", "obj3"},
|
||||
Operations: ops,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("all updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, _ string) (smartblock.SmartBlock, error) {
|
||||
return nil, fmt.Errorf("failed to find object")
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.ModifyDetailsList(&pb.RpcObjectListModifyDetailValuesRequest{
|
||||
ObjectIds: []string{"obj1", "obj2", "obj3"},
|
||||
Operations: ops,
|
||||
})
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_SetSpaceInfo(t *testing.T) {
|
||||
var (
|
||||
wsObjectId = "workspace"
|
||||
details = &types.Struct{Fields: map[string]*types.Value{
|
||||
bundle.RelationKeyName.String(): pbtypes.String("My space"),
|
||||
bundle.RelationKeyIconOption.String(): pbtypes.Int64(5),
|
||||
bundle.RelationKeyIconImage.String(): pbtypes.String("kitten.jpg"),
|
||||
}}
|
||||
)
|
||||
|
||||
t.Run("no error", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
ws := smarttest.New(wsObjectId)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: wsObjectId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, wsObjectId, objectId)
|
||||
return ws, nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetSpaceInfo(spaceId, details)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "My space", pbtypes.GetString(ws.NewState().Details(), bundle.RelationKeyName.String()))
|
||||
assert.Equal(t, int64(5), pbtypes.GetInt64(ws.NewState().Details(), bundle.RelationKeyIconOption.String()))
|
||||
assert.Equal(t, "kitten.jpg", pbtypes.GetString(ws.NewState().Details(), bundle.RelationKeyIconImage.String()))
|
||||
})
|
||||
|
||||
t.Run("error on details setting", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: wsObjectId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, wsObjectId, objectId)
|
||||
return nil, fmt.Errorf("failed to get object")
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetSpaceInfo(spaceId, details)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_SetWorkspaceDashboardId(t *testing.T) {
|
||||
var (
|
||||
wsObjectId = "workspace"
|
||||
dashboardId = "homepage"
|
||||
)
|
||||
|
||||
t.Run("no error", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(wsObjectId)
|
||||
sb.SetType(coresb.SmartBlockTypeWorkspace)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, wsObjectId, objectId)
|
||||
ws := &editor.Workspaces{
|
||||
SmartBlock: sb,
|
||||
AllOperations: basic.NewBasic(sb, fx.store, nil, nil, nil),
|
||||
}
|
||||
return ws, nil
|
||||
})
|
||||
|
||||
// when
|
||||
setId, err := fx.SetWorkspaceDashboardId(nil, wsObjectId, dashboardId)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, dashboardId, setId)
|
||||
assert.Equal(t, dashboardId, pbtypes.GetString(sb.NewState().Details(), bundle.RelationKeySpaceDashboardId.String()))
|
||||
})
|
||||
|
||||
t.Run("error if wrong smartblock type", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(wsObjectId)
|
||||
sb.SetType(coresb.SmartBlockTypePage)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
assert.Equal(t, wsObjectId, objectId)
|
||||
ws := &editor.Workspaces{
|
||||
SmartBlock: sb,
|
||||
AllOperations: basic.NewBasic(sb, fx.store, nil, nil, nil),
|
||||
}
|
||||
return ws, nil
|
||||
})
|
||||
|
||||
// when
|
||||
_, err := fx.SetWorkspaceDashboardId(nil, wsObjectId, dashboardId)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, ErrUnexpectedBlockType, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_SetListIsFavorite(t *testing.T) {
|
||||
var (
|
||||
objects = []objectstore.TestObject{
|
||||
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
{bundle.RelationKeyId: pbtypes.String("obj2"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
{bundle.RelationKeyId: pbtypes.String("obj3"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
}
|
||||
homeId = "home"
|
||||
)
|
||||
|
||||
t.Run("no error on favoriting", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(homeId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: homeId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Home: homeId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
require.Equal(t, homeId, objectId)
|
||||
return editor.NewDashboard(sb, fx.store, nil), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsFavorite([]string{"obj1", "obj2", "obj3"}, true)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 4)
|
||||
})
|
||||
|
||||
t.Run("no error on unfavoriting", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(homeId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: homeId, ChildrenIds: []string{"obj1", "obj2", "obj3"}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj1", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj1"}}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj2", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj2"}}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj3", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj3"}}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Home: homeId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
require.Equal(t, homeId, objectId)
|
||||
return editor.NewDashboard(sb, fx.store, nil), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsFavorite([]string{"obj3", "obj1"}, false)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 2)
|
||||
})
|
||||
|
||||
t.Run("some updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(homeId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: homeId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Home: homeId})
|
||||
flag := false
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
require.Equal(t, homeId, objectId)
|
||||
if flag {
|
||||
return nil, fmt.Errorf("unexpected error")
|
||||
}
|
||||
flag = true
|
||||
return editor.NewDashboard(sb, fx.store, nil), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsFavorite([]string{"obj3", "obj1"}, true)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 2)
|
||||
})
|
||||
|
||||
t.Run("all updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Home: homeId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
require.Equal(t, homeId, objectId)
|
||||
return nil, fmt.Errorf("unexpected error")
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsFavorite([]string{"obj3", "obj1"}, true)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_SetIsArchived(t *testing.T) {
|
||||
var (
|
||||
objects = []objectstore.TestObject{
|
||||
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
}
|
||||
binId = "bin"
|
||||
)
|
||||
|
||||
t.Run("no error on moving to bin", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(binId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: binId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Archive: binId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId == binId {
|
||||
return editor.NewArchive(sb, fx.store), nil
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
fx.restriction.EXPECT().CheckRestrictions(mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// when
|
||||
err := fx.SetIsArchived("obj1", true)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 2)
|
||||
})
|
||||
|
||||
t.Run("cannot move to bin an object with restriction", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(binId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: binId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId == binId {
|
||||
return editor.NewArchive(sb, fx.store), nil
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
fx.restriction.EXPECT().CheckRestrictions(mock.Anything, mock.Anything).Return(restriction.ErrRestricted)
|
||||
|
||||
// when
|
||||
err := fx.SetIsArchived("obj1", true)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, restriction.ErrRestricted)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_SetListIsArchived(t *testing.T) {
|
||||
var (
|
||||
objects = []objectstore.TestObject{
|
||||
{bundle.RelationKeyId: pbtypes.String("obj1"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
{bundle.RelationKeyId: pbtypes.String("obj2"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
{bundle.RelationKeyId: pbtypes.String("obj3"), bundle.RelationKeySpaceId: pbtypes.String(spaceId)},
|
||||
}
|
||||
binId = "bin"
|
||||
)
|
||||
|
||||
t.Run("no error on moving to bin", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(binId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: binId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Archive: binId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId == binId {
|
||||
return editor.NewArchive(sb, fx.store), nil
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
fx.restriction.EXPECT().CheckRestrictions(mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// when
|
||||
err := fx.SetListIsArchived([]string{"obj1", "obj2", "obj3"}, true)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 4)
|
||||
})
|
||||
|
||||
t.Run("no error on moving from bin", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
|
||||
sb := smarttest.New(binId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: binId, ChildrenIds: []string{"obj1", "obj2", "obj3"}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj1", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj1"}}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj2", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj2"}}}))
|
||||
sb.AddBlock(simple.New(&model.Block{Id: "obj3", Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{TargetBlockId: "obj3"}}}))
|
||||
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Archive: binId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId == binId {
|
||||
return editor.NewArchive(sb, fx.store), nil
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsArchived([]string{"obj1", "obj2", "obj3"}, false)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 1)
|
||||
})
|
||||
|
||||
t.Run("some updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
sb := smarttest.New(binId)
|
||||
sb.AddBlock(simple.New(&model.Block{Id: binId, ChildrenIds: []string{}}))
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Archive: binId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
if objectId == binId {
|
||||
return editor.NewArchive(sb, fx.store), nil
|
||||
}
|
||||
if objectId == "obj2" {
|
||||
return nil, fmt.Errorf("failed to get object")
|
||||
}
|
||||
return smarttest.New(objectId), nil
|
||||
})
|
||||
fx.restriction.EXPECT().CheckRestrictions(mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// when
|
||||
err := fx.SetListIsArchived([]string{"obj1", "obj2", "obj3"}, true)
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, sb.Blocks(), 3)
|
||||
})
|
||||
|
||||
t.Run("all updates failed", func(t *testing.T) {
|
||||
// given
|
||||
fx := newFixture(t)
|
||||
fx.store.AddObjects(t, objects)
|
||||
fx.space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Archive: binId})
|
||||
fx.space.EXPECT().GetObject(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, objectId string) (smartblock.SmartBlock, error) {
|
||||
return nil, fmt.Errorf("failed to get object")
|
||||
})
|
||||
|
||||
// when
|
||||
err := fx.SetListIsArchived([]string{"obj1", "obj2", "obj3"}, true)
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
|
@ -107,7 +107,7 @@ func (s *service) SetIsArchived(objectId string, isArchived bool) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("get space: %w", err)
|
||||
}
|
||||
if err := s.checkArchivedRestriction(isArchived, spaceID, objectId); err != nil {
|
||||
if err := s.checkArchivedRestriction(isArchived, objectId); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.objectLinksCollectionModify(spc.DerivedIDs().Archive, objectId, isArchived)
|
||||
|
@ -166,7 +166,7 @@ func (s *service) SetListIsArchived(objectIds []string, isArchived bool) error {
|
|||
return multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (s *service) checkArchivedRestriction(isArchived bool, spaceID string, objectId string) error {
|
||||
func (s *service) checkArchivedRestriction(isArchived bool, objectId string) error {
|
||||
if !isArchived {
|
||||
return nil
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ func (s *service) setIsArchivedForObjects(spaceID string, objectIDs []string, is
|
|||
}
|
||||
for _, id := range ids {
|
||||
var err error
|
||||
if restrErr := s.checkArchivedRestriction(isArchived, spaceID, id); restrErr != nil {
|
||||
if restrErr := s.checkArchivedRestriction(isArchived, id); restrErr != nil {
|
||||
err = restrErr
|
||||
} else {
|
||||
if isArchived {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/threads"
|
||||
"github.com/anyproto/anytype-heart/util/pbtypes"
|
||||
"github.com/anyproto/anytype-heart/util/testMock"
|
||||
)
|
||||
|
||||
|
@ -268,6 +269,49 @@ func (st *SmartTest) SetDetails(ctx session.Context, details []*model.Detail, sh
|
|||
return
|
||||
}
|
||||
|
||||
func (st *SmartTest) SetDetailsAndUpdateLastUsed(ctx session.Context, details []*model.Detail, showEvent bool) (err error) {
|
||||
for _, detail := range details {
|
||||
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, detail.Key)
|
||||
}
|
||||
return st.SetDetails(ctx, details, showEvent)
|
||||
}
|
||||
|
||||
func (st *SmartTest) UpdateDetails(update func(current *types.Struct) (*types.Struct, error)) (err error) {
|
||||
details := st.Doc.(*state.State).CombinedDetails()
|
||||
if details == nil || details.Fields == nil {
|
||||
details = &types.Struct{Fields: map[string]*types.Value{}}
|
||||
}
|
||||
newDetails, err := update(details)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st.Doc.(*state.State).SetDetails(newDetails)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *SmartTest) UpdateDetailsAndLastUsed(update func(current *types.Struct) (*types.Struct, error)) (err error) {
|
||||
details := st.Doc.(*state.State).CombinedDetails()
|
||||
if details == nil || details.Fields == nil {
|
||||
details = &types.Struct{Fields: map[string]*types.Value{}}
|
||||
}
|
||||
oldDetails := pbtypes.CopyStruct(details, true)
|
||||
|
||||
newDetails, err := update(details)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
diff := pbtypes.StructDiff(oldDetails, newDetails)
|
||||
if diff == nil || diff.Fields == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for key := range diff.Fields {
|
||||
st.Results.LastUsedUpdates = append(st.Results.LastUsedUpdates, key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *SmartTest) Init(ctx *smartblock.InitContext) (err error) {
|
||||
if ctx.State == nil {
|
||||
ctx.State = st.NewState()
|
||||
|
@ -408,4 +452,6 @@ func (st *SmartTest) Update(ctx session.Context, apply func(b simple.Block) erro
|
|||
type Results struct {
|
||||
Events [][]simple.EventMessage
|
||||
Applies [][]*model.Block
|
||||
|
||||
LastUsedUpdates []string
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue