391 lines
9.5 KiB
Go
391 lines
9.5 KiB
Go
package mongo_test
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/sunboyy/repogen/internal/code"
|
|
"github.com/sunboyy/repogen/internal/codegen"
|
|
"github.com/sunboyy/repogen/internal/mongo"
|
|
"github.com/sunboyy/repogen/internal/spec"
|
|
)
|
|
|
|
var (
|
|
idField = code.StructField{
|
|
Name: "ID",
|
|
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
|
|
Tag: `bson:"_id,omitempty"`,
|
|
}
|
|
genderField = code.StructField{
|
|
Name: "Gender",
|
|
Type: code.SimpleType("Gender"),
|
|
Tag: `bson:"gender"`,
|
|
}
|
|
ageField = code.StructField{
|
|
Name: "Age",
|
|
Type: code.TypeInt,
|
|
Tag: `bson:"age"`,
|
|
}
|
|
nameField = code.StructField{
|
|
Name: "Name",
|
|
Type: code.SimpleType("NameModel"),
|
|
Tag: `bson:"name"`,
|
|
}
|
|
referrerField = code.StructField{
|
|
Name: "Referrer",
|
|
Type: code.PointerType{ContainedType: code.SimpleType("UserModel")},
|
|
Tag: `bson:"referrer"`,
|
|
}
|
|
consentHistoryField = code.StructField{
|
|
Name: "ConsentHistory",
|
|
Type: code.ArrayType{ContainedType: code.SimpleType("ConsentHistory")},
|
|
Tag: `bson:"consent_history"`,
|
|
}
|
|
enabledField = code.StructField{
|
|
Name: "Enabled",
|
|
Type: code.TypeBool,
|
|
Tag: `bson:"enabled"`,
|
|
}
|
|
accessTokenField = code.StructField{
|
|
Name: "AccessToken",
|
|
Type: code.TypeString,
|
|
}
|
|
|
|
firstNameField = code.StructField{
|
|
Name: "First",
|
|
Type: code.TypeString,
|
|
Tag: `bson:"first"`,
|
|
}
|
|
)
|
|
|
|
var userModel = code.Struct{
|
|
Name: "UserModel",
|
|
Fields: code.StructFields{
|
|
idField,
|
|
code.StructField{
|
|
Name: "Username",
|
|
Type: code.TypeString,
|
|
Tag: `bson:"username"`,
|
|
},
|
|
genderField,
|
|
ageField,
|
|
nameField,
|
|
referrerField,
|
|
consentHistoryField,
|
|
enabledField,
|
|
accessTokenField,
|
|
},
|
|
}
|
|
|
|
func TestImports(t *testing.T) {
|
|
generator := mongo.NewGenerator(userModel, "UserRepository")
|
|
expected := [][]code.Import{
|
|
{
|
|
{Path: "context"},
|
|
},
|
|
{
|
|
{Path: "go.mongodb.org/mongo-driver/bson"},
|
|
{Path: "go.mongodb.org/mongo-driver/bson/primitive"},
|
|
{Path: "go.mongodb.org/mongo-driver/mongo"},
|
|
{Path: "go.mongodb.org/mongo-driver/mongo/options"},
|
|
},
|
|
}
|
|
|
|
actual := generator.Imports()
|
|
|
|
if !reflect.DeepEqual(expected, actual) {
|
|
t.Errorf("incorrect imports: expected %+v, got %+v", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestGenerateStruct(t *testing.T) {
|
|
generator := mongo.NewGenerator(userModel, "UserRepository")
|
|
expected := codegen.StructBuilder{
|
|
Name: "UserRepositoryMongo",
|
|
Fields: []code.StructField{
|
|
{
|
|
Name: "collection",
|
|
Type: code.PointerType{
|
|
ContainedType: code.ExternalType{
|
|
PackageAlias: "mongo",
|
|
Name: "Collection",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
actual := generator.GenerateStruct()
|
|
|
|
if expected.Name != actual.Name {
|
|
t.Errorf(
|
|
"incorrect struct name: expected %s, got %s",
|
|
expected.Name,
|
|
actual.Name,
|
|
)
|
|
}
|
|
if !reflect.DeepEqual(expected.Fields, actual.Fields) {
|
|
t.Errorf(
|
|
"incorrect struct fields: expected %+v, got %+v",
|
|
expected.Fields,
|
|
actual.Fields,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestGenerateConstructor(t *testing.T) {
|
|
generator := mongo.NewGenerator(userModel, "UserRepository")
|
|
expected := codegen.FunctionBuilder{
|
|
Name: "NewUserRepository",
|
|
Params: []code.Param{
|
|
{
|
|
Name: "collection",
|
|
Type: code.PointerType{
|
|
ContainedType: code.ExternalType{
|
|
PackageAlias: "mongo",
|
|
Name: "Collection",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Returns: []code.Type{
|
|
code.SimpleType("UserRepository"),
|
|
},
|
|
Body: codegen.FunctionBody{
|
|
codegen.ReturnStatement{
|
|
codegen.StructStatement{
|
|
Type: "&UserRepositoryMongo",
|
|
Pairs: []codegen.StructFieldPair{{
|
|
Key: "collection",
|
|
Value: codegen.Identifier("collection"),
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
actual, err := generator.GenerateConstructor()
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if expected.Name != actual.Name {
|
|
t.Errorf(
|
|
"incorrect function name: expected %s, got %s",
|
|
expected.Name,
|
|
actual.Name,
|
|
)
|
|
}
|
|
if !reflect.DeepEqual(expected.Params, actual.Params) {
|
|
t.Errorf(
|
|
"incorrect struct params: expected %+v, got %+v",
|
|
expected.Params,
|
|
actual.Params,
|
|
)
|
|
}
|
|
if !reflect.DeepEqual(expected.Body, actual.Body) {
|
|
t.Errorf("incorrect function body: expected %+v got %+v",
|
|
expected.Body,
|
|
actual.Body,
|
|
)
|
|
}
|
|
}
|
|
|
|
type GenerateMethodTestCase struct {
|
|
Name string
|
|
MethodSpec spec.MethodSpec
|
|
ExpectedBody string
|
|
}
|
|
|
|
type GenerateMethodInvalidTestCase struct {
|
|
Name string
|
|
Method spec.MethodSpec
|
|
ExpectedError error
|
|
}
|
|
|
|
type StubOperation struct {
|
|
}
|
|
|
|
func (o StubOperation) Name() string {
|
|
return "Stub"
|
|
}
|
|
|
|
func TestGenerateMethod_Invalid(t *testing.T) {
|
|
testTable := []GenerateMethodInvalidTestCase{
|
|
{
|
|
Name: "operation not supported",
|
|
Method: spec.MethodSpec{
|
|
Name: "SearchByID",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
|
},
|
|
Returns: []code.Type{
|
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
code.TypeError,
|
|
},
|
|
Operation: StubOperation{},
|
|
},
|
|
ExpectedError: mongo.NewOperationNotSupportedError("Stub"),
|
|
},
|
|
{
|
|
Name: "bson tag not found in query",
|
|
Method: spec.MethodSpec{
|
|
Name: "FindByAccessToken",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
{Type: code.TypeString},
|
|
},
|
|
Returns: []code.Type{
|
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
code.TypeError,
|
|
},
|
|
Operation: spec.FindOperation{
|
|
Mode: spec.QueryModeOne,
|
|
Query: spec.QuerySpec{
|
|
Predicates: []spec.Predicate{
|
|
{
|
|
FieldReference: spec.FieldReference{accessTokenField},
|
|
Comparator: spec.ComparatorEqual,
|
|
ParamIndex: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedError: mongo.NewBsonTagNotFoundError("AccessToken"),
|
|
},
|
|
{
|
|
Name: "bson tag not found in sort",
|
|
Method: spec.MethodSpec{
|
|
Name: "FindAllOrderByAccessToken",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
},
|
|
Returns: []code.Type{
|
|
code.ArrayType{ContainedType: code.PointerType{ContainedType: code.SimpleType("UserModel")}},
|
|
code.TypeError,
|
|
},
|
|
Operation: spec.FindOperation{
|
|
Mode: spec.QueryModeOne,
|
|
Sorts: []spec.Sort{
|
|
{FieldReference: spec.FieldReference{accessTokenField}, Ordering: spec.OrderingAscending},
|
|
},
|
|
},
|
|
},
|
|
ExpectedError: mongo.NewBsonTagNotFoundError("AccessToken"),
|
|
},
|
|
{
|
|
Name: "bson tag not found in update field",
|
|
Method: spec.MethodSpec{
|
|
Name: "UpdateAccessTokenByID",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
{Type: code.TypeString},
|
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
|
},
|
|
Returns: []code.Type{
|
|
code.TypeBool,
|
|
code.TypeError,
|
|
},
|
|
Operation: spec.UpdateOperation{
|
|
Update: spec.UpdateFields{
|
|
spec.UpdateField{
|
|
FieldReference: spec.FieldReference{accessTokenField},
|
|
ParamIndex: 1,
|
|
Operator: spec.UpdateOperatorSet,
|
|
},
|
|
},
|
|
Mode: spec.QueryModeOne,
|
|
Query: spec.QuerySpec{
|
|
Predicates: []spec.Predicate{
|
|
{
|
|
FieldReference: spec.FieldReference{idField},
|
|
Comparator: spec.ComparatorEqual,
|
|
ParamIndex: 2,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedError: mongo.NewBsonTagNotFoundError("AccessToken"),
|
|
},
|
|
{
|
|
Name: "update type not supported",
|
|
Method: spec.MethodSpec{
|
|
Name: "UpdateAgeByID",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
{Type: code.TypeInt},
|
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
|
},
|
|
Returns: []code.Type{
|
|
code.TypeBool,
|
|
code.TypeError,
|
|
},
|
|
Operation: spec.UpdateOperation{
|
|
Update: StubUpdate{},
|
|
Mode: spec.QueryModeOne,
|
|
Query: spec.QuerySpec{
|
|
Predicates: []spec.Predicate{
|
|
{
|
|
FieldReference: spec.FieldReference{idField},
|
|
Comparator: spec.ComparatorEqual,
|
|
ParamIndex: 2,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedError: mongo.NewUpdateTypeNotSupportedError(StubUpdate{}),
|
|
},
|
|
{
|
|
Name: "update operator not supported",
|
|
Method: spec.MethodSpec{
|
|
Name: "UpdateConsentHistoryAppendByID",
|
|
Params: []code.Param{
|
|
{Type: code.ExternalType{PackageAlias: "context", Name: "Context"}},
|
|
{Type: code.TypeInt},
|
|
{Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}},
|
|
},
|
|
Returns: []code.Type{
|
|
code.TypeBool,
|
|
code.TypeError,
|
|
},
|
|
Operation: spec.UpdateOperation{
|
|
Update: spec.UpdateFields{
|
|
spec.UpdateField{
|
|
FieldReference: spec.FieldReference{consentHistoryField},
|
|
ParamIndex: 1,
|
|
Operator: "APPEND",
|
|
},
|
|
},
|
|
Mode: spec.QueryModeOne,
|
|
Query: spec.QuerySpec{
|
|
Predicates: []spec.Predicate{
|
|
{
|
|
FieldReference: spec.FieldReference{idField},
|
|
Comparator: spec.ComparatorEqual,
|
|
ParamIndex: 2,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ExpectedError: mongo.NewUpdateOperatorNotSupportedError("APPEND"),
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testTable {
|
|
t.Run(testCase.Name, func(t *testing.T) {
|
|
generator := mongo.NewGenerator(userModel, "UserRepository")
|
|
|
|
_, err := generator.GenerateMethod(testCase.Method)
|
|
|
|
if !errors.Is(err, testCase.ExpectedError) {
|
|
t.Errorf("\nExpected = %+v\nReceived = %+v", testCase.ExpectedError, err)
|
|
}
|
|
})
|
|
}
|
|
}
|