Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(server): Increase domain package unit test coverage (integrationapi part 2) #1307

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions server/pkg/id/id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,16 @@ func TestAsset_Type(t *testing.T) {

r := Resource{}
assert.Equal(t, "resource", r.Type())

v := View{}
assert.Equal(t, "request", v.Type())
Comment on lines +59 to +60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

The View.Type() method incorrectly returns "request" instead of "view"

The implementation in server/pkg/id/id.go confirms that View.Type() returns "request", which breaks the consistent pattern where entity types match their lowercase names (e.g., Tag returns "tag", Group returns "group"). This should be changed to return "view" instead.

  • server/pkg/id/id.go:246: Change func (View) Type() string { return "request" } to func (View) Type() string { return "view" }
🔗 Analysis chain

Verify the expected type for View entity

The test asserts that View.Type() returns "request", which seems incorrect as it doesn't match the entity name pattern seen in other tests. Other entities return their lowercase name as the type (e.g., Tag returns "tag", Group returns "group").

Let's verify the correct type by checking the View entity implementation:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find the View entity implementation to verify its Type() method
ast-grep --pattern 'type View struct {
  $$$
}'

# Find the Type() method implementation for View
ast-grep --pattern 'func (View) Type() string {
  $$$
}'

Length of output: 2711


tag := Tag{}
assert.Equal(t, "tag", tag.Type())

g := Group{}
assert.Equal(t, "group", g.Type())

ig := ItemGroup{}
assert.Equal(t, "item_group", ig.Type())
}
11 changes: 11 additions & 0 deletions server/pkg/id/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,14 @@ func TestKey_Clone(t *testing.T) {
assert.Equal(t, k, c)
assert.NotSame(t, k, c)
}

func TestKey_NewKeyFromPtr(t *testing.T) {

str := "test-key"
wantKey := Key{
key: lo.FromPtr(&str),
}
result := NewKeyFromPtr(&str)
assert.NotNil(t, result, "Result should not be nil")
assert.Equal(t, &wantKey, result, "Key value should match the input string")
}
174 changes: 174 additions & 0 deletions server/pkg/integrationapi/event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package integrationapi

import (
"testing"
"time"

"github.com/reearth/reearth-cms/server/pkg/asset"
"github.com/reearth/reearth-cms/server/pkg/event"
"github.com/reearth/reearth-cms/server/pkg/id"
"github.com/reearth/reearth-cms/server/pkg/operator"
"github.com/reearth/reearth-cms/server/pkg/project"
"github.com/reearth/reearthx/account/accountdomain"
"github.com/reearth/reearthx/account/accountdomain/user"
"github.com/stretchr/testify/assert"
)

func Test_NewOperator(t *testing.T) {

uid := accountdomain.NewUserID()
integrationID := id.NewIntegrationID()
opUser := operator.OperatorFromUser(uid)
opIntegration := operator.OperatorFromIntegration(integrationID)
opMachine := operator.OperatorFromMachine()
tests := []struct {
name string
input operator.Operator
want Operator
}{
{
name: "success user operator",
input: opUser,
want: Operator{
User: &OperatorUser{
ID: uid.String(),
},
},
},
{
name: "success integration operator",
input: opIntegration,
want: Operator{
Integration: &OperatorIntegration{
ID: integrationID.String(),
},
},
},
{
name: "success machine operator",
input: opMachine,
want: Operator{
Machine: &OperatorMachine{},
},
},
{
name: "success unknown operator",
input: operator.Operator{},
want: Operator{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
result := NewOperator(test.input)
if !assert.Equal(t, result, test.want) {
t.Errorf("expected %+v but got %+v", test.want, result)
}
})

}
}

func TestNewEventWith(t *testing.T) {
mockTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
u := user.New().NewID().Email("[email protected]").Name("John").MustBuild()
a := asset.New().NewID().Project(project.NewID()).Size(100).NewUUID().
CreatedByUser(u.ID()).Thread(id.NewThreadID()).MustBuild()
eID1 := event.NewID()
prj := event.Project{
ID: "testID",
Alias: "testAlias",
}

ev := event.New[any]().ID(eID1).Timestamp(mockTime).Type(event.AssetCreate).Operator(operator.OperatorFromUser(u.ID())).Object(a).Project(&prj).MustBuild()
ev1 := event.New[any]().ID(eID1).Timestamp(mockTime).Type(event.Type("test")).Operator(operator.OperatorFromUser(u.ID())).Object("test").Project(&prj).MustBuild()
d1, _ := New(ev, "test", func(a *asset.Asset) string {
return "test.com"
})
d2, _ := New(ev.Object(), "test", func(a *asset.Asset) string {
return "test.com"
})
type args struct {
event *event.Event[any]
override any
v string
urlResolver asset.URLResolver
}
tests := []struct {
name string
args args
want Event
wantErr error
}{
{
name: "success",
args: args{
event: ev,
override: ev,
v: "test",
urlResolver: func(a *asset.Asset) string {
return "test.com"
},
},
want: Event{
ID: ev.ID().String(),
Type: string(ev.Type()),
Timestamp: ev.Timestamp(),
Data: d1,
Project: &ProjectIdAlias{
ID: ev.Project().ID,
Alias: ev.Project().Alias,
},
Operator: NewOperator(ev.Operator()),
},
wantErr: nil,
},
{
name: "success when override is nil",
args: args{
event: ev,
override: nil,
v: "test",
urlResolver: func(a *asset.Asset) string {
return "test.com"
},
},
want: Event{
ID: ev.ID().String(),
Type: string(ev.Type()),
Timestamp: ev.Timestamp(),
Data: d2,
Project: &ProjectIdAlias{
ID: ev.Project().ID,
Alias: ev.Project().Alias,
},
Operator: NewOperator(ev.Operator()),
},
wantErr: nil,
},
{
name: "error new returns error",
args: args{
event: ev,
override: ev1,
v: "",
urlResolver: nil,
},
want: Event{},
wantErr: ErrUnsupportedEntity,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

result, err := NewEventWith(test.args.event, test.args.override, test.args.v, test.args.urlResolver)
if !assert.Equal(t, result, test.want) {
t.Errorf("expected %+v but got %+v", test.want, result)
}
if !assert.Equal(t, err, test.wantErr) {
t.Errorf("expected %+v but got %+v", test.wantErr, err)
}
})
}
}
144 changes: 144 additions & 0 deletions server/pkg/integrationapi/schema_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package integrationapi

import (
"testing"
"time"

"github.com/reearth/reearth-cms/server/pkg/id"
"github.com/reearth/reearth-cms/server/pkg/item"
"github.com/reearth/reearth-cms/server/pkg/model"
"github.com/reearth/reearth-cms/server/pkg/schema"
"github.com/reearth/reearth-cms/server/pkg/value"
"github.com/reearth/reearthx/account/accountdomain"
"github.com/reearth/reearthx/util"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
)

func TestNewModel(t *testing.T) {
type args struct {
m *model.Model
sp *schema.Package
lastModified time.Time
}
mockTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
pID := id.NewProjectID()
sf1 := schema.NewField(schema.NewText(nil).TypeProperty()).NewID().RandomKey().MustBuild()
sf2 := schema.NewField(lo.Must1(schema.NewInteger(nil, nil)).TypeProperty()).NewID().RandomKey().MustBuild()
s1 := schema.New().NewID().Project(pID).Workspace(accountdomain.NewWorkspaceID()).Fields([]*schema.Field{sf1, sf2}).MustBuild()
s2 := schema.New().NewID().Project(pID).Workspace(accountdomain.NewWorkspaceID()).Fields([]*schema.Field{sf1, sf2}).TitleField(sf1.ID().Ref()).MustBuild()
schemaPackage1 := schema.NewPackage(s1, nil, nil, nil)
schemaPackage2 := schema.NewPackage(s2, nil, nil, nil)
model1 := model.New().ID(id.NewModelID()).Metadata(s1.ID().Ref()).Project(pID).Schema(s1.ID()).Key(id.NewKey("mmm123")).UpdatedAt(mockTime).MustBuild()
model2 := model.New().ID(id.NewModelID()).Metadata(s2.ID().Ref()).Project(pID).Schema(s2.ID()).Key(id.NewKey("mmm123")).UpdatedAt(mockTime).MustBuild()

tests := []struct {
name string
args args
want Model
}{
{
name: "success",
args: args{
m: model1,
sp: schemaPackage1,
lastModified: mockTime,
},
want: Model{
Id: model1.ID().Ref(),
Key: util.ToPtrIfNotEmpty(model1.Key().String()),
Name: util.ToPtrIfNotEmpty(model1.Name()),
Description: util.ToPtrIfNotEmpty(model1.Description()),
Public: util.ToPtrIfNotEmpty(model1.Public()),
ProjectId: model1.Project().Ref(),
SchemaId: model1.Schema().Ref(),
Schema: util.ToPtrIfNotEmpty(NewSchema(schemaPackage1.Schema())),
MetadataSchemaId: model1.Metadata().Ref(),
MetadataSchema: util.ToPtrIfNotEmpty(NewSchema(schemaPackage1.MetaSchema())),
CreatedAt: lo.ToPtr(model1.ID().Timestamp()),
UpdatedAt: lo.ToPtr(model1.UpdatedAt()),
LastModified: util.ToPtrIfNotEmpty(mockTime),
},
},
{
name: "success with item field in schema",
args: args{
m: model2,
sp: schemaPackage2,
lastModified: mockTime,
},
want: Model{
Id: model2.ID().Ref(),
Key: util.ToPtrIfNotEmpty(model2.Key().String()),
Name: util.ToPtrIfNotEmpty(model2.Name()),
Description: util.ToPtrIfNotEmpty(model2.Description()),
Public: util.ToPtrIfNotEmpty(model2.Public()),
ProjectId: model2.Project().Ref(),
SchemaId: model2.Schema().Ref(),
Schema: util.ToPtrIfNotEmpty(NewSchema(schemaPackage2.Schema())),
MetadataSchemaId: model2.Metadata().Ref(),
MetadataSchema: util.ToPtrIfNotEmpty(NewSchema(schemaPackage2.MetaSchema())),
CreatedAt: lo.ToPtr(model2.ID().Timestamp()),
UpdatedAt: lo.ToPtr(model2.UpdatedAt()),
LastModified: util.ToPtrIfNotEmpty(mockTime),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result := NewModel(tt.args.m, tt.args.sp, tt.args.lastModified)
assert.Equal(t, tt.want, result)
})
}
}

func TestNewItemFieldChanges(t *testing.T) {

fID := id.NewFieldID()
v0 := value.MultipleFrom(value.TypeBool, []*value.Value{
value.New(value.TypeBool, false),
})
v1 := value.MultipleFrom(value.TypeBool, []*value.Value{
value.New(value.TypeBool, true),
})

type args struct {
change item.FieldChanges
}

tests := []struct {
name string
args args
want []FieldChange
}{
{
name: "success",
args: args{
change: item.FieldChanges{
item.FieldChange{
ID: fID,
Type: item.FieldChangeTypeAdd,
CurrentValue: value.MultipleFrom(v1.Type(), []*value.Value{v1.First()}),
PreviousValue: value.MultipleFrom(v0.Type(), []*value.Value{v0.First()}),
},
},
},
want: []FieldChange{
{
ID: fID,
Type: item.FieldChangeTypeAdd,
CurrentValue: v1.Interface(),
PreviousValue: v0.Interface(),
},
},
},
}
for _, test := range tests {
t.Run(string(test.name), func(t *testing.T) {
t.Parallel()
result := NewItemFieldChanges(test.args.change)
assert.Equal(t, test.want, result)
})
}
}
Comment on lines +96 to +144
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage with additional test cases.

While the test is well-structured, it could benefit from more comprehensive coverage:

  1. Add test cases for other field change types (Update, Remove)
  2. Include tests for different value types (String, Number, etc.)
  3. Add test cases for edge cases (nil values, empty changes)

Example additional test cases:

 tests := []struct {
     name string
     args args
     want []FieldChange
 }{
+    {
+        name: "update change type",
+        args: args{
+            change: item.FieldChanges{
+                item.FieldChange{
+                    ID:            fID,
+                    Type:          item.FieldChangeTypeUpdate,
+                    CurrentValue:  value.New(value.TypeString, "new"),
+                    PreviousValue: value.New(value.TypeString, "old"),
+                },
+            },
+        },
+        want: []FieldChange{
+            {
+                ID:            fID,
+                Type:          item.FieldChangeTypeUpdate,
+                CurrentValue:  "new",
+                PreviousValue: "old",
+            },
+        },
+    },
+    {
+        name: "empty changes",
+        args: args{
+            change: item.FieldChanges{},
+        },
+        want: []FieldChange{},
+    },
     // existing test cases...
 }

Committable suggestion skipped: line range outside the PR's diff.

18 changes: 18 additions & 0 deletions server/pkg/item/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,21 @@ func TestBuilder_IsMetadata(t *testing.T) {
b := New().IsMetadata(true)
assert.Equal(t, true, b.i.isMetadata)
}

func TestBuilder_UpdatedByUser(t *testing.T) {
uId := accountdomain.NewUserID()
uuid := New().UpdatedByUser(&uId)
assert.Equal(t, &uId, uuid.i.updatedByUser)
}

func TestBuilder_UpdatedByIntegration(t *testing.T) {
iid := id.NewIntegrationID()
uuid := New().UpdatedByIntegration(&iid)
assert.Equal(t, &iid, uuid.i.updatedByIntegration)
}

func TestBuilder_OriginalItem(t *testing.T) {
iId := id.NewItemID().Ref()
b := New().OriginalItem(iId)
assert.Equal(t, iId, b.i.originalItem)
}