mirror of https://github.com/stashapp/stash.git
3008 lines
70 KiB
Go
3008 lines
70 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package sqlite_test
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var invalidID = -1
|
|
|
|
func loadGalleryRelationships(ctx context.Context, expected models.Gallery, actual *models.Gallery) error {
|
|
if expected.URLs.Loaded() {
|
|
if err := actual.LoadURLs(ctx, db.Gallery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if expected.SceneIDs.Loaded() {
|
|
if err := actual.LoadSceneIDs(ctx, db.Gallery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if expected.TagIDs.Loaded() {
|
|
if err := actual.LoadTagIDs(ctx, db.Gallery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if expected.PerformerIDs.Loaded() {
|
|
if err := actual.LoadPerformerIDs(ctx, db.Gallery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if expected.Files.Loaded() {
|
|
if err := actual.LoadFiles(ctx, db.Gallery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// clear Path, Checksum, PrimaryFileID
|
|
if expected.Path == "" {
|
|
actual.Path = ""
|
|
}
|
|
if expected.PrimaryFileID == nil {
|
|
actual.PrimaryFileID = nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_Create(t *testing.T) {
|
|
var (
|
|
title = "title"
|
|
code = "1337"
|
|
url = "url"
|
|
rating = 60
|
|
details = "details"
|
|
photographer = "photographer"
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
galleryFile = makeFileWithID(fileIdxStartGalleryFiles)
|
|
)
|
|
|
|
date, _ := models.ParseDate("2003-02-01")
|
|
|
|
tests := []struct {
|
|
name string
|
|
newObject models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
models.Gallery{
|
|
Title: title,
|
|
Code: code,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
Date: &date,
|
|
Details: details,
|
|
Photographer: photographer,
|
|
Rating: &rating,
|
|
Organized: true,
|
|
StudioID: &studioIDs[studioIdxWithScene],
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"with file",
|
|
models.Gallery{
|
|
Title: title,
|
|
Code: code,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
Date: &date,
|
|
Details: details,
|
|
Photographer: photographer,
|
|
Rating: &rating,
|
|
Organized: true,
|
|
StudioID: &studioIDs[studioIdxWithScene],
|
|
Files: models.NewRelatedFiles([]models.File{
|
|
galleryFile,
|
|
}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid studio id",
|
|
models.Gallery{
|
|
StudioID: &invalidID,
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid scene id",
|
|
models.Gallery{
|
|
SceneIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid tag id",
|
|
models.Gallery{
|
|
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid performer id",
|
|
models.Gallery{
|
|
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
},
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
s := tt.newObject
|
|
var fileIDs []models.FileID
|
|
if s.Files.Loaded() {
|
|
fileIDs = []models.FileID{s.Files.List()[0].Base().ID}
|
|
}
|
|
|
|
if err := qb.Create(ctx, &s, fileIDs); (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.Create() error = %v, wantErr = %v", err, tt.wantErr)
|
|
}
|
|
|
|
if tt.wantErr {
|
|
assert.Zero(s.ID)
|
|
return
|
|
}
|
|
|
|
assert.NotZero(s.ID)
|
|
|
|
copy := tt.newObject
|
|
copy.ID = s.ID
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, copy, &s); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(copy, s)
|
|
|
|
// ensure can find the scene
|
|
found, err := qb.Find(ctx, s.ID)
|
|
if err != nil {
|
|
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
|
|
}
|
|
|
|
if !assert.NotNil(found) {
|
|
return
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, copy, found); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(copy, *found)
|
|
|
|
return
|
|
})
|
|
}
|
|
}
|
|
|
|
func makeGalleryFileWithID(i int) *models.BaseFile {
|
|
ret := makeGalleryFile(i)
|
|
ret.ID = galleryFileIDs[i]
|
|
return ret
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_Update(t *testing.T) {
|
|
var (
|
|
title = "title"
|
|
code = "code"
|
|
url = "url"
|
|
rating = 60
|
|
details = "details"
|
|
photographer = "photographer"
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
date, _ := models.ParseDate("2003-02-01")
|
|
|
|
tests := []struct {
|
|
name string
|
|
updatedObject *models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithScene],
|
|
Title: title,
|
|
Code: code,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
Date: &date,
|
|
Details: details,
|
|
Photographer: photographer,
|
|
Rating: &rating,
|
|
Organized: true,
|
|
StudioID: &studioIDs[studioIdxWithScene],
|
|
Files: models.NewRelatedFiles([]models.File{
|
|
makeGalleryFileWithID(galleryIdxWithScene),
|
|
}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithScene]}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear nullables",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
URLs: models.NewRelatedStrings([]string{}),
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{}),
|
|
Organized: true,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear scene ids",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithScene],
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{}),
|
|
Organized: true,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear tag ids",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithTag],
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{}),
|
|
Organized: true,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear performer ids",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithPerformer],
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{}),
|
|
Organized: true,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid studio id",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Organized: true,
|
|
StudioID: &invalidID,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid scene id",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Organized: true,
|
|
SceneIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid tag id",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Organized: true,
|
|
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid performer id",
|
|
&models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Organized: true,
|
|
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
copy := *tt.updatedObject
|
|
|
|
if err := qb.Update(ctx, tt.updatedObject); (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.Update() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
s, err := qb.Find(ctx, tt.updatedObject.ID)
|
|
if err != nil {
|
|
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
|
|
return
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, copy, s); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(copy, *s)
|
|
|
|
return
|
|
})
|
|
}
|
|
}
|
|
|
|
func clearGalleryFileIDs(gallery *models.Gallery) {
|
|
if gallery.Files.Loaded() {
|
|
for _, f := range gallery.Files.List() {
|
|
f.Base().ID = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
func clearGalleryPartial() models.GalleryPartial {
|
|
// leave mandatory fields
|
|
return models.GalleryPartial{
|
|
Title: models.OptionalString{Set: true, Null: true},
|
|
Code: models.OptionalString{Set: true, Null: true},
|
|
Details: models.OptionalString{Set: true, Null: true},
|
|
Photographer: models.OptionalString{Set: true, Null: true},
|
|
URLs: &models.UpdateStrings{Mode: models.RelationshipUpdateModeSet},
|
|
Date: models.OptionalDate{Set: true, Null: true},
|
|
Rating: models.OptionalInt{Set: true, Null: true},
|
|
StudioID: models.OptionalInt{Set: true, Null: true},
|
|
TagIDs: &models.UpdateIDs{Mode: models.RelationshipUpdateModeSet},
|
|
PerformerIDs: &models.UpdateIDs{Mode: models.RelationshipUpdateModeSet},
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
|
|
var (
|
|
title = "title"
|
|
code = "code"
|
|
details = "details"
|
|
photographer = "photographer"
|
|
url = "url"
|
|
rating = 60
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
date, _ = models.ParseDate("2003-02-01")
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
id int
|
|
partial models.GalleryPartial
|
|
want models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
galleryIDs[galleryIdxWithImage],
|
|
models.GalleryPartial{
|
|
Title: models.NewOptionalString(title),
|
|
Code: models.NewOptionalString(code),
|
|
Details: models.NewOptionalString(details),
|
|
Photographer: models.NewOptionalString(photographer),
|
|
URLs: &models.UpdateStrings{
|
|
Values: []string{url},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
Date: models.NewOptionalDate(date),
|
|
Rating: models.NewOptionalInt(rating),
|
|
Organized: models.NewOptionalBool(true),
|
|
StudioID: models.NewOptionalInt(studioIDs[studioIdxWithGallery]),
|
|
CreatedAt: models.NewOptionalTime(createdAt),
|
|
UpdatedAt: models.NewOptionalTime(updatedAt),
|
|
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{sceneIDs[sceneIdxWithGallery]},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithGallery], tagIDs[tagIdx1WithDupName]},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{performerIDs[performerIdx1WithGallery], performerIDs[performerIdx1WithDupName]},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Title: title,
|
|
Code: code,
|
|
Details: details,
|
|
Photographer: photographer,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
Date: &date,
|
|
Rating: &rating,
|
|
Organized: true,
|
|
StudioID: &studioIDs[studioIdxWithGallery],
|
|
Files: models.NewRelatedFiles([]models.File{
|
|
makeGalleryFile(galleryIdxWithImage),
|
|
}),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdxWithGallery]}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithGallery], tagIDs[tagIdx1WithDupName]}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithGallery], performerIDs[performerIdx1WithDupName]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear all",
|
|
galleryIDs[galleryIdxWithImage],
|
|
clearGalleryPartial(),
|
|
models.Gallery{
|
|
ID: galleryIDs[galleryIdxWithImage],
|
|
Files: models.NewRelatedFiles([]models.File{
|
|
makeGalleryFile(galleryIdxWithImage),
|
|
}),
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
PerformerIDs: models.NewRelatedIDs([]int{}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid id",
|
|
invalidID,
|
|
models.GalleryPartial{},
|
|
models.Gallery{},
|
|
true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
qb := db.Gallery
|
|
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
got, err := qb.UpdatePartial(ctx, tt.id, tt.partial)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.UpdatePartial() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
clearGalleryFileIDs(got)
|
|
assert.Equal(tt.want, *got)
|
|
|
|
s, err := qb.Find(ctx, tt.id)
|
|
if err != nil {
|
|
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, tt.want, s); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
clearGalleryFileIDs(s)
|
|
assert.Equal(tt.want, *s)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
id int
|
|
partial models.GalleryPartial
|
|
want models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"add scenes",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
models.GalleryPartial{
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[sceneIdx1WithStudio], tagIDs[sceneIdx1WithPerformer]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
SceneIDs: models.NewRelatedIDs(append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdx1WithImage)),
|
|
sceneIDs[sceneIdx1WithStudio],
|
|
sceneIDs[sceneIdx1WithPerformer],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
models.GalleryPartial{
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithImage]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
|
|
tagIDs[tagIdx1WithDupName],
|
|
tagIDs[tagIdx1WithImage],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
models.GalleryPartial{
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{performerIDs[performerIdx1WithDupName], performerIDs[performerIdx1WithImage]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
|
|
performerIDs[performerIdx1WithDupName],
|
|
performerIDs[performerIdx1WithImage],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add duplicate scenes",
|
|
galleryIDs[galleryIdxWithScene],
|
|
models.GalleryPartial{
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{sceneIDs[sceneIdxWithGallery], sceneIDs[sceneIdx1WithPerformer]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
SceneIDs: models.NewRelatedIDs(append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdxWithScene)),
|
|
sceneIDs[sceneIdx1WithPerformer],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add duplicate tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
models.GalleryPartial{
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithGallery], tagIDs[tagIdx1WithScene]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
|
|
tagIDs[tagIdx1WithScene],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add duplicate performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
models.GalleryPartial{
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{performerIDs[performerIdx1WithGallery], performerIDs[performerIdx1WithScene]},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
|
|
performerIDs[performerIdx1WithScene],
|
|
)),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"add invalid scenes",
|
|
galleryIDs[galleryIdxWithScene],
|
|
models.GalleryPartial{
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{invalidID},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{},
|
|
true,
|
|
},
|
|
{
|
|
"add invalid tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
models.GalleryPartial{
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{invalidID},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{},
|
|
true,
|
|
},
|
|
{
|
|
"add invalid performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
models.GalleryPartial{
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{invalidID},
|
|
Mode: models.RelationshipUpdateModeAdd,
|
|
},
|
|
},
|
|
models.Gallery{},
|
|
true,
|
|
},
|
|
{
|
|
"remove scenes",
|
|
galleryIDs[galleryIdxWithScene],
|
|
models.GalleryPartial{
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{sceneIDs[sceneIdxWithGallery]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
SceneIDs: models.NewRelatedIDs([]int{}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"remove tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
models.GalleryPartial{
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithGallery]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx2WithGallery]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"remove performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
models.GalleryPartial{
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{performerIDs[performerIdx1WithGallery]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx2WithGallery]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"remove unrelated scenes",
|
|
galleryIDs[galleryIdxWithScene],
|
|
models.GalleryPartial{
|
|
SceneIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[sceneIdx1WithPerformer]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdxWithGallery]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"remove unrelated tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
models.GalleryPartial{
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithPerformer]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
TagIDs: models.NewRelatedIDs(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags])),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"remove unrelated performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
models.GalleryPartial{
|
|
PerformerIDs: &models.UpdateIDs{
|
|
IDs: []int{performerIDs[performerIdx1WithDupName]},
|
|
Mode: models.RelationshipUpdateModeRemove,
|
|
},
|
|
},
|
|
models.Gallery{
|
|
PerformerIDs: models.NewRelatedIDs(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers])),
|
|
},
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
qb := db.Gallery
|
|
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
got, err := qb.UpdatePartial(ctx, tt.id, tt.partial)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.UpdatePartial() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
s, err := qb.Find(ctx, tt.id)
|
|
if err != nil {
|
|
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
if err := loadGalleryRelationships(ctx, tt.want, s); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
// only compare fields that were in the partial
|
|
if tt.partial.PerformerIDs != nil {
|
|
assert.ElementsMatch(tt.want.PerformerIDs.List(), got.PerformerIDs.List())
|
|
assert.ElementsMatch(tt.want.PerformerIDs.List(), s.PerformerIDs.List())
|
|
}
|
|
if tt.partial.TagIDs != nil {
|
|
assert.ElementsMatch(tt.want.TagIDs.List(), got.TagIDs.List())
|
|
assert.ElementsMatch(tt.want.TagIDs.List(), s.TagIDs.List())
|
|
}
|
|
if tt.partial.SceneIDs != nil {
|
|
assert.ElementsMatch(tt.want.SceneIDs.List(), got.SceneIDs.List())
|
|
assert.ElementsMatch(tt.want.SceneIDs.List(), s.SceneIDs.List())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_Destroy(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
id int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
galleryIDs[galleryIdxWithScene],
|
|
false,
|
|
},
|
|
{
|
|
"invalid",
|
|
invalidID,
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
if err := qb.Destroy(ctx, tt.id); (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.Destroy() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
|
|
// ensure cannot be found
|
|
i, err := qb.Find(ctx, tt.id)
|
|
|
|
assert.Nil(err)
|
|
assert.Nil(i)
|
|
return
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func makeGalleryWithID(index int) *models.Gallery {
|
|
const includeScenes = true
|
|
ret := makeGallery(index, includeScenes)
|
|
ret.ID = galleryIDs[index]
|
|
|
|
ret.Files = models.NewRelatedFiles([]models.File{makeGalleryFile(index)})
|
|
|
|
return ret
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_Find(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
id int
|
|
want *models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
galleryIDs[galleryIdxWithImage],
|
|
makeGalleryWithID(galleryIdxWithImage),
|
|
false,
|
|
},
|
|
{
|
|
"invalid",
|
|
invalidID,
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
"with performers",
|
|
galleryIDs[galleryIdxWithTwoPerformers],
|
|
makeGalleryWithID(galleryIdxWithTwoPerformers),
|
|
false,
|
|
},
|
|
{
|
|
"with tags",
|
|
galleryIDs[galleryIdxWithTwoTags],
|
|
makeGalleryWithID(galleryIdxWithTwoTags),
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.Find(ctx, tt.id)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.Find() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if got != nil {
|
|
// load relationships
|
|
if err := loadGalleryRelationships(ctx, *tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
clearGalleryFileIDs(got)
|
|
}
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func postFindGalleries(ctx context.Context, want []*models.Gallery, got []*models.Gallery) error {
|
|
for i, s := range got {
|
|
// load relationships
|
|
if i < len(want) {
|
|
if err := loadGalleryRelationships(ctx, *want[i], s); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
clearGalleryFileIDs(s)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindMany(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid with relationships",
|
|
[]int{galleryIDs[galleryIdxWithImage], galleryIDs[galleryIdxWithTwoPerformers], galleryIDs[galleryIdxWithTwoTags]},
|
|
[]*models.Gallery{
|
|
makeGalleryWithID(galleryIdxWithImage),
|
|
makeGalleryWithID(galleryIdxWithTwoPerformers),
|
|
makeGalleryWithID(galleryIdxWithTwoTags),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid",
|
|
[]int{galleryIDs[galleryIdxWithImage], galleryIDs[galleryIdxWithTwoPerformers], invalidID},
|
|
nil,
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindMany(ctx, tt.ids)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindMany() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindByChecksum(t *testing.T) {
|
|
getChecksum := func(index int) string {
|
|
return getGalleryStringValue(index, checksumField)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
checksum string
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
getChecksum(galleryIdxWithImage),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithImage)},
|
|
false,
|
|
},
|
|
{
|
|
"invalid",
|
|
"invalid checksum",
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
"with performers",
|
|
getChecksum(galleryIdxWithTwoPerformers),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithTwoPerformers)},
|
|
false,
|
|
},
|
|
{
|
|
"with tags",
|
|
getChecksum(galleryIdxWithTwoTags),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithTwoTags)},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByChecksum(ctx, tt.checksum)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindByChecksum() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindByChecksums(t *testing.T) {
|
|
getChecksum := func(index int) string {
|
|
return getGalleryStringValue(index, checksumField)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
checksums []string
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid with relationships",
|
|
[]string{
|
|
getChecksum(galleryIdxWithImage),
|
|
getChecksum(galleryIdxWithTwoPerformers),
|
|
getChecksum(galleryIdxWithTwoTags),
|
|
},
|
|
[]*models.Gallery{
|
|
makeGalleryWithID(galleryIdxWithImage),
|
|
makeGalleryWithID(galleryIdxWithTwoPerformers),
|
|
makeGalleryWithID(galleryIdxWithTwoTags),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"with invalid",
|
|
[]string{
|
|
getChecksum(galleryIdxWithImage),
|
|
getChecksum(galleryIdxWithTwoPerformers),
|
|
"invalid checksum",
|
|
getChecksum(galleryIdxWithTwoTags),
|
|
},
|
|
[]*models.Gallery{
|
|
makeGalleryWithID(galleryIdxWithImage),
|
|
makeGalleryWithID(galleryIdxWithTwoPerformers),
|
|
makeGalleryWithID(galleryIdxWithTwoTags),
|
|
},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByChecksums(ctx, tt.checksums)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindByChecksum() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindByPath(t *testing.T) {
|
|
getPath := func(index int) string {
|
|
return getFilePath(folderIdxWithGalleryFiles, getGalleryBasename(index))
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
getPath(galleryIdxWithImage),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithImage)},
|
|
false,
|
|
},
|
|
{
|
|
"invalid",
|
|
"invalid path",
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
"with performers",
|
|
getPath(galleryIdxWithTwoPerformers),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithTwoPerformers)},
|
|
false,
|
|
},
|
|
{
|
|
"with tags",
|
|
getPath(galleryIdxWithTwoTags),
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithTwoTags)},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByPath(ctx, tt.path)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindByPath() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindBySceneID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
sceneID int
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
sceneIDs[sceneIdxWithGallery],
|
|
[]*models.Gallery{makeGalleryWithID(galleryIdxWithScene)},
|
|
false,
|
|
},
|
|
{
|
|
"none",
|
|
sceneIDs[sceneIdx1WithPerformer],
|
|
nil,
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindBySceneID(ctx, tt.sceneID)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindBySceneID() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_FindByImageID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
imageID int
|
|
want []*models.Gallery
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
imageIDs[imageIdxWithTwoGalleries],
|
|
[]*models.Gallery{
|
|
makeGalleryWithID(galleryIdx1WithImage),
|
|
makeGalleryWithID(galleryIdx2WithImage),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"none",
|
|
imageIDs[imageIdx1WithPerformer],
|
|
nil,
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByImageID(ctx, tt.imageID)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.FindByImageID() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if err := postFindGalleries(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadGalleryRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryQueryBuilder_CountByImageID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
imageID int
|
|
want int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"valid",
|
|
imageIDs[imageIdxWithTwoGalleries],
|
|
2,
|
|
false,
|
|
},
|
|
{
|
|
"none",
|
|
imageIDs[imageIdx1WithPerformer],
|
|
0,
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
got, err := qb.CountByImageID(ctx, tt.imageID)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("galleryQueryBuilder.CountByImageID() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("galleryQueryBuilder.CountByImageID() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func galleriesToIDs(i []*models.Gallery) []int {
|
|
var ret []int
|
|
for _, ii := range i {
|
|
ret = append(ret, ii.ID)
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func Test_galleryStore_FindByFileID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
fileID models.FileID
|
|
include []int
|
|
exclude []int
|
|
}{
|
|
{
|
|
"valid",
|
|
galleryFileIDs[galleryIdx1WithImage],
|
|
[]int{galleryIdx1WithImage},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid",
|
|
invalidFileID,
|
|
nil,
|
|
[]int{galleryIdx1WithImage},
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByFileID(ctx, tt.fileID)
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.FindByFileID() error = %v", err)
|
|
return
|
|
}
|
|
for _, f := range got {
|
|
clearGalleryFileIDs(f)
|
|
}
|
|
|
|
ids := galleriesToIDs(got)
|
|
include := indexesToIDs(galleryIDs, tt.include)
|
|
exclude := indexesToIDs(galleryIDs, tt.exclude)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_galleryStore_FindByFolderID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
folderID models.FolderID
|
|
include []int
|
|
exclude []int
|
|
}{
|
|
// TODO - add folder gallery
|
|
{
|
|
"invalid",
|
|
invalidFolderID,
|
|
nil,
|
|
[]int{galleryIdxWithImage},
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, err := qb.FindByFolderID(ctx, tt.folderID)
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.FindByFolderID() error = %v", err)
|
|
return
|
|
}
|
|
for _, f := range got {
|
|
clearGalleryFileIDs(f)
|
|
}
|
|
|
|
ids := galleriesToIDs(got)
|
|
include := indexesToIDs(imageIDs, tt.include)
|
|
exclude := indexesToIDs(imageIDs, tt.exclude)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryQ(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
const galleryIdx = 0
|
|
|
|
q := getGalleryStringValue(galleryIdx, pathField)
|
|
galleryQueryQ(ctx, t, q, galleryIdx)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func galleryQueryQ(ctx context.Context, t *testing.T, q string, expectedGalleryIdx int) {
|
|
qb := db.Gallery
|
|
|
|
filter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
galleries, _, err := qb.Query(ctx, nil, &filter)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
assert.Len(t, galleries, 1)
|
|
gallery := galleries[0]
|
|
assert.Equal(t, galleryIDs[expectedGalleryIdx], gallery.ID)
|
|
|
|
// no Q should return all results
|
|
filter.Q = nil
|
|
galleries, _, err = qb.Query(ctx, nil, &filter)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
assert.Len(t, galleries, totalGalleries)
|
|
}
|
|
|
|
func TestGalleryQueryPath(t *testing.T) {
|
|
const galleryIdx = 1
|
|
galleryPath := getFilePath(folderIdxWithGalleryFiles, getGalleryBasename(galleryIdx))
|
|
|
|
tests := []struct {
|
|
name string
|
|
input models.StringCriterionInput
|
|
}{
|
|
{
|
|
"equals",
|
|
models.StringCriterionInput{
|
|
Value: galleryPath,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
},
|
|
{
|
|
"not equals",
|
|
models.StringCriterionInput{
|
|
Value: galleryPath,
|
|
Modifier: models.CriterionModifierNotEquals,
|
|
},
|
|
},
|
|
{
|
|
"matches regex",
|
|
models.StringCriterionInput{
|
|
Value: "gallery.*1_Path",
|
|
Modifier: models.CriterionModifierMatchesRegex,
|
|
},
|
|
},
|
|
{
|
|
"not matches regex",
|
|
models.StringCriterionInput{
|
|
Value: "gallery.*1_Path",
|
|
Modifier: models.CriterionModifierNotMatchesRegex,
|
|
},
|
|
},
|
|
{
|
|
"is null",
|
|
models.StringCriterionInput{
|
|
Modifier: models.CriterionModifierIsNull,
|
|
},
|
|
},
|
|
{
|
|
"not null",
|
|
models.StringCriterionInput{
|
|
Modifier: models.CriterionModifierNotNull,
|
|
},
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
got, count, err := qb.Query(ctx, &models.GalleryFilterType{
|
|
Path: &tt.input,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.TestSceneQueryPath() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.NotEqual(t, 0, count)
|
|
|
|
for _, gallery := range got {
|
|
verifyString(t, gallery.Path, tt.input)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func verifyGalleriesPath(ctx context.Context, t *testing.T, pathCriterion models.StringCriterionInput) {
|
|
galleryFilter := models.GalleryFilterType{
|
|
Path: &pathCriterion,
|
|
}
|
|
|
|
sqb := db.Gallery
|
|
galleries, _, err := sqb.Query(ctx, &galleryFilter, nil)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
for _, gallery := range galleries {
|
|
verifyString(t, gallery.Path, pathCriterion)
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryPathOr(t *testing.T) {
|
|
const gallery1Idx = 1
|
|
const gallery2Idx = 2
|
|
|
|
gallery1Path := getFilePath(folderIdxWithGalleryFiles, getGalleryBasename(gallery1Idx))
|
|
gallery2Path := getFilePath(folderIdxWithGalleryFiles, getGalleryBasename(gallery2Idx))
|
|
|
|
galleryFilter := models.GalleryFilterType{
|
|
Path: &models.StringCriterionInput{
|
|
Value: gallery1Path,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
OperatorFilter: models.OperatorFilter[models.GalleryFilterType]{
|
|
Or: &models.GalleryFilterType{
|
|
Path: &models.StringCriterionInput{
|
|
Value: gallery2Path,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
|
|
if !assert.Len(t, galleries, 2) {
|
|
return nil
|
|
}
|
|
|
|
assert.Equal(t, gallery1Path, galleries[0].Path)
|
|
assert.Equal(t, gallery2Path, galleries[1].Path)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryPathAndRating(t *testing.T) {
|
|
const galleryIdx = 1
|
|
galleryPath := getFilePath(folderIdxWithGalleryFiles, getGalleryBasename(galleryIdx))
|
|
galleryRating := getIntPtr(getRating(galleryIdx))
|
|
|
|
galleryFilter := models.GalleryFilterType{
|
|
Path: &models.StringCriterionInput{
|
|
Value: galleryPath,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
OperatorFilter: models.OperatorFilter[models.GalleryFilterType]{
|
|
And: &models.GalleryFilterType{
|
|
Rating100: &models.IntCriterionInput{
|
|
Value: *galleryRating,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
|
|
if !assert.Len(t, galleries, 1) {
|
|
return nil
|
|
}
|
|
|
|
assert.Equal(t, galleryPath, galleries[0].Path)
|
|
assert.Equal(t, *galleryRating, *galleries[0].Rating)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryPathNotRating(t *testing.T) {
|
|
const galleryIdx = 1
|
|
|
|
galleryRating := getRating(galleryIdx)
|
|
|
|
pathCriterion := models.StringCriterionInput{
|
|
Value: "gallery_.*1_Path",
|
|
Modifier: models.CriterionModifierMatchesRegex,
|
|
}
|
|
|
|
ratingCriterion := models.IntCriterionInput{
|
|
Value: int(galleryRating.Int64),
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
galleryFilter := models.GalleryFilterType{
|
|
Path: &pathCriterion,
|
|
OperatorFilter: models.OperatorFilter[models.GalleryFilterType]{
|
|
Not: &models.GalleryFilterType{
|
|
Rating100: &ratingCriterion,
|
|
},
|
|
},
|
|
}
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
|
|
for _, gallery := range galleries {
|
|
verifyString(t, gallery.Path, pathCriterion)
|
|
ratingCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyIntPtr(t, gallery.Rating, ratingCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryIllegalQuery(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
const galleryIdx = 1
|
|
subFilter := models.GalleryFilterType{
|
|
Path: &models.StringCriterionInput{
|
|
Value: getGalleryStringValue(galleryIdx, "Path"),
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
}
|
|
|
|
galleryFilter := &models.GalleryFilterType{
|
|
OperatorFilter: models.OperatorFilter[models.GalleryFilterType]{
|
|
And: &subFilter,
|
|
Or: &subFilter,
|
|
},
|
|
}
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
|
|
_, _, err := sqb.Query(ctx, galleryFilter, nil)
|
|
assert.NotNil(err)
|
|
|
|
galleryFilter.Or = nil
|
|
galleryFilter.Not = &subFilter
|
|
_, _, err = sqb.Query(ctx, galleryFilter, nil)
|
|
assert.NotNil(err)
|
|
|
|
galleryFilter.And = nil
|
|
galleryFilter.Or = &subFilter
|
|
_, _, err = sqb.Query(ctx, galleryFilter, nil)
|
|
assert.NotNil(err)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryURL(t *testing.T) {
|
|
const sceneIdx = 1
|
|
galleryURL := getGalleryStringValue(sceneIdx, urlField)
|
|
|
|
urlCriterion := models.StringCriterionInput{
|
|
Value: galleryURL,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
filter := models.GalleryFilterType{
|
|
URL: &urlCriterion,
|
|
}
|
|
|
|
verifyFn := func(g *models.Gallery) {
|
|
t.Helper()
|
|
urls := g.URLs.List()
|
|
var url string
|
|
if len(urls) > 0 {
|
|
url = urls[0]
|
|
}
|
|
|
|
verifyString(t, url, urlCriterion)
|
|
}
|
|
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierMatchesRegex
|
|
urlCriterion.Value = "gallery_.*1_URL"
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotMatchesRegex
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierIsNull
|
|
urlCriterion.Value = ""
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotNull
|
|
verifyGalleryQuery(t, filter, verifyFn)
|
|
}
|
|
|
|
func verifyGalleryQuery(t *testing.T, filter models.GalleryFilterType, verifyFn func(s *models.Gallery)) {
|
|
withTxn(func(ctx context.Context) error {
|
|
t.Helper()
|
|
sqb := db.Gallery
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &filter, nil)
|
|
|
|
for _, g := range galleries {
|
|
if err := g.LoadURLs(ctx, sqb); err != nil {
|
|
t.Errorf("Error loading gallery URLs: %v", err)
|
|
}
|
|
}
|
|
|
|
// assume it should find at least one
|
|
assert.Greater(t, len(galleries), 0)
|
|
|
|
for _, gallery := range galleries {
|
|
verifyFn(gallery)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryRating100(t *testing.T) {
|
|
const rating = 60
|
|
ratingCriterion := models.IntCriterionInput{
|
|
Value: rating,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
|
|
ratingCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
|
|
ratingCriterion.Modifier = models.CriterionModifierGreaterThan
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
|
|
ratingCriterion.Modifier = models.CriterionModifierLessThan
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
|
|
ratingCriterion.Modifier = models.CriterionModifierIsNull
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
|
|
ratingCriterion.Modifier = models.CriterionModifierNotNull
|
|
verifyGalleriesRating100(t, ratingCriterion)
|
|
}
|
|
|
|
func verifyGalleriesRating100(t *testing.T, ratingCriterion models.IntCriterionInput) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
galleryFilter := models.GalleryFilterType{
|
|
Rating100: &ratingCriterion,
|
|
}
|
|
|
|
galleries, _, err := sqb.Query(ctx, &galleryFilter, nil)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
for _, gallery := range galleries {
|
|
verifyIntPtr(t, gallery.Rating, ratingCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryIsMissingScene(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
qb := db.Gallery
|
|
isMissing := "scenes"
|
|
galleryFilter := models.GalleryFilterType{
|
|
IsMissing: &isMissing,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithScene, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries, _, err := qb.Query(ctx, &galleryFilter, &findFilter)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
assert.Len(t, galleries, 0)
|
|
|
|
findFilter.Q = nil
|
|
galleries, _, err = qb.Query(ctx, &galleryFilter, &findFilter)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
// ensure non of the ids equal the one with gallery
|
|
for _, gallery := range galleries {
|
|
assert.NotEqual(t, galleryIDs[galleryIdxWithScene], gallery.ID)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func queryGallery(ctx context.Context, t *testing.T, sqb models.GalleryReader, galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) []*models.Gallery {
|
|
galleries, _, err := sqb.Query(ctx, galleryFilter, findFilter)
|
|
if err != nil {
|
|
t.Errorf("Error querying gallery: %s", err.Error())
|
|
}
|
|
|
|
return galleries
|
|
}
|
|
|
|
func TestGalleryQueryIsMissingStudio(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
isMissing := "studio"
|
|
galleryFilter := models.GalleryFilterType{
|
|
IsMissing: &isMissing,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithStudio, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.Len(t, galleries, 0)
|
|
|
|
findFilter.Q = nil
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
// ensure non of the ids equal the one with studio
|
|
for _, gallery := range galleries {
|
|
assert.NotEqual(t, galleryIDs[galleryIdxWithStudio], gallery.ID)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryIsMissingPerformers(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
isMissing := "performers"
|
|
galleryFilter := models.GalleryFilterType{
|
|
IsMissing: &isMissing,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithPerformer, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.Len(t, galleries, 0)
|
|
|
|
findFilter.Q = nil
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.True(t, len(galleries) > 0)
|
|
|
|
// ensure non of the ids equal the one with galleries
|
|
for _, gallery := range galleries {
|
|
assert.NotEqual(t, galleryIDs[galleryIdxWithPerformer], gallery.ID)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryIsMissingTags(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
isMissing := "tags"
|
|
galleryFilter := models.GalleryFilterType{
|
|
IsMissing: &isMissing,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithTwoTags, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.Len(t, galleries, 0)
|
|
|
|
findFilter.Q = nil
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.True(t, len(galleries) > 0)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryIsMissingDate(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
isMissing := "date"
|
|
galleryFilter := models.GalleryFilterType{
|
|
IsMissing: &isMissing,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
|
|
// one in four galleries have no date
|
|
assert.Len(t, galleries, int(math.Ceil(float64(totalGalleries)/4)))
|
|
|
|
// ensure date is null
|
|
for _, g := range galleries {
|
|
assert.Nil(t, g.Date)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryPerformers(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
filter models.MultiCriterionInput
|
|
includeIdxs []int
|
|
excludeIdxs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"includes",
|
|
models.MultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(performerIDs[performerIdxWithGallery]),
|
|
strconv.Itoa(performerIDs[performerIdx1WithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithTwoPerformers,
|
|
},
|
|
[]int{
|
|
galleryIdxWithImage,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"includes all",
|
|
models.MultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(performerIDs[performerIdx1WithGallery]),
|
|
strconv.Itoa(performerIDs[performerIdx2WithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
},
|
|
[]int{
|
|
galleryIdxWithTwoPerformers,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"excludes",
|
|
models.MultiCriterionInput{
|
|
Modifier: models.CriterionModifierExcludes,
|
|
Value: []string{strconv.Itoa(tagIDs[performerIdx1WithGallery])},
|
|
},
|
|
nil,
|
|
[]int{galleryIdxWithTwoPerformers},
|
|
false,
|
|
},
|
|
{
|
|
"is null",
|
|
models.MultiCriterionInput{
|
|
Modifier: models.CriterionModifierIsNull,
|
|
},
|
|
[]int{galleryIdxWithTag},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithTwoPerformers,
|
|
galleryIdxWithPerformerTwoTags,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"not null",
|
|
models.MultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotNull,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithTwoPerformers,
|
|
galleryIdxWithPerformerTwoTags,
|
|
},
|
|
[]int{galleryIdxWithTag},
|
|
false,
|
|
},
|
|
{
|
|
"equals",
|
|
models.MultiCriterionInput{
|
|
Modifier: models.CriterionModifierEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[performerIdx1WithGallery]),
|
|
strconv.Itoa(tagIDs[performerIdx2WithGallery]),
|
|
},
|
|
},
|
|
[]int{galleryIdxWithTwoPerformers},
|
|
[]int{
|
|
galleryIdxWithThreePerformers,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"not equals",
|
|
models.MultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[performerIdx1WithGallery]),
|
|
strconv.Itoa(tagIDs[performerIdx2WithGallery]),
|
|
},
|
|
},
|
|
nil,
|
|
nil,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
results, _, err := db.Gallery.Query(ctx, &models.GalleryFilterType{
|
|
Performers: &tt.filter,
|
|
}, nil)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("GalleryStore.Query() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
ids := galleriesToIDs(results)
|
|
|
|
include := indexesToIDs(galleryIDs, tt.includeIdxs)
|
|
exclude := indexesToIDs(galleryIDs, tt.excludeIdxs)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryTags(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
filter models.HierarchicalMultiCriterionInput
|
|
includeIdxs []int
|
|
excludeIdxs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"includes",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdxWithGallery]),
|
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
[]int{
|
|
galleryIdxWithTag,
|
|
galleryIdxWithTwoTags,
|
|
},
|
|
[]int{
|
|
galleryIdxWithImage,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"includes all",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
|
strconv.Itoa(tagIDs[tagIdx2WithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
},
|
|
[]int{
|
|
galleryIdxWithTwoTags,
|
|
},
|
|
[]int{
|
|
galleryIdxWithTag,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"excludes",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierExcludes,
|
|
Value: []string{strconv.Itoa(tagIDs[tagIdx1WithGallery])},
|
|
},
|
|
nil,
|
|
[]int{galleryIdxWithTwoTags},
|
|
false,
|
|
},
|
|
{
|
|
"is null",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierIsNull,
|
|
},
|
|
[]int{galleryIdx1WithPerformer},
|
|
[]int{
|
|
galleryIdxWithTag,
|
|
galleryIdxWithTwoTags,
|
|
galleryIdxWithThreeTags,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"not null",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotNull,
|
|
},
|
|
[]int{
|
|
galleryIdxWithTag,
|
|
galleryIdxWithTwoTags,
|
|
galleryIdxWithThreeTags,
|
|
},
|
|
[]int{galleryIdx1WithPerformer},
|
|
false,
|
|
},
|
|
{
|
|
"equals",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
|
strconv.Itoa(tagIDs[tagIdx2WithGallery]),
|
|
},
|
|
},
|
|
[]int{galleryIdxWithTwoTags},
|
|
[]int{
|
|
galleryIdxWithThreeTags,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"not equals",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
|
strconv.Itoa(tagIDs[tagIdx2WithGallery]),
|
|
},
|
|
},
|
|
nil,
|
|
nil,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
results, _, err := db.Gallery.Query(ctx, &models.GalleryFilterType{
|
|
Tags: &tt.filter,
|
|
}, nil)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("GalleryStore.Query() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
ids := galleriesToIDs(results)
|
|
|
|
include := indexesToIDs(imageIDs, tt.includeIdxs)
|
|
exclude := indexesToIDs(imageIDs, tt.excludeIdxs)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryStudio(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
q string
|
|
studioCriterion models.HierarchicalMultiCriterionInput
|
|
expectedIDs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"includes",
|
|
"",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
[]int{galleryIDs[galleryIdxWithStudio]},
|
|
false,
|
|
},
|
|
{
|
|
"excludes",
|
|
getGalleryStringValue(galleryIdxWithStudio, titleField),
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierExcludes,
|
|
},
|
|
[]int{},
|
|
false,
|
|
},
|
|
{
|
|
"excludes includes null",
|
|
getGalleryStringValue(galleryIdxWithImage, titleField),
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierExcludes,
|
|
},
|
|
[]int{galleryIDs[galleryIdxWithImage]},
|
|
false,
|
|
},
|
|
{
|
|
"equals",
|
|
"",
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
[]int{galleryIDs[galleryIdxWithStudio]},
|
|
false,
|
|
},
|
|
{
|
|
"not equals",
|
|
getGalleryStringValue(galleryIdxWithStudio, titleField),
|
|
models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
|
},
|
|
Modifier: models.CriterionModifierNotEquals,
|
|
},
|
|
[]int{},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
studioCriterion := tt.studioCriterion
|
|
|
|
galleryFilter := models.GalleryFilterType{
|
|
Studios: &studioCriterion,
|
|
}
|
|
|
|
var findFilter *models.FindFilterType
|
|
if tt.q != "" {
|
|
findFilter = &models.FindFilterType{
|
|
Q: &tt.q,
|
|
}
|
|
}
|
|
|
|
gallerys := queryGallery(ctx, t, qb, &galleryFilter, findFilter)
|
|
|
|
assert.ElementsMatch(t, galleriesToIDs(gallerys), tt.expectedIDs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryStudioDepth(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
depth := 2
|
|
studioCriterion := models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGrandChild]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
Depth: &depth,
|
|
}
|
|
|
|
galleryFilter := models.GalleryFilterType{
|
|
Studios: &studioCriterion,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Len(t, galleries, 1)
|
|
|
|
depth = 1
|
|
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Len(t, galleries, 0)
|
|
|
|
studioCriterion.Value = []string{strconv.Itoa(studioIDs[studioIdxWithParentAndChild])}
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Len(t, galleries, 1)
|
|
|
|
// ensure id is correct
|
|
assert.Equal(t, galleryIDs[galleryIdxWithGrandChildStudio], galleries[0].ID)
|
|
|
|
depth = 2
|
|
|
|
studioCriterion = models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithGrandChild]),
|
|
},
|
|
Modifier: models.CriterionModifierExcludes,
|
|
Depth: &depth,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithGrandChildStudio, pathField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
assert.Len(t, galleries, 0)
|
|
|
|
depth = 1
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
assert.Len(t, galleries, 1)
|
|
|
|
studioCriterion.Value = []string{strconv.Itoa(studioIDs[studioIdxWithParentAndChild])}
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
assert.Len(t, galleries, 0)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryPerformerTags(t *testing.T) {
|
|
allDepth := -1
|
|
|
|
tests := []struct {
|
|
name string
|
|
findFilter *models.FindFilterType
|
|
filter *models.GalleryFilterType
|
|
includeIdxs []int
|
|
excludeIdxs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"includes",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdxWithPerformer]),
|
|
strconv.Itoa(tagIDs[tagIdx1WithPerformer]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformerTag,
|
|
galleryIdxWithPerformerTwoTags,
|
|
galleryIdxWithTwoPerformerTag,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"includes sub-tags",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdxWithParentAndChild]),
|
|
},
|
|
Depth: &allDepth,
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformerParentTag,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithPerformerTag,
|
|
galleryIdxWithPerformerTwoTags,
|
|
galleryIdxWithTwoPerformerTag,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"includes all",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithPerformer]),
|
|
strconv.Itoa(tagIDs[tagIdx2WithPerformer]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
},
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformerTwoTags,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithPerformerTag,
|
|
galleryIdxWithTwoPerformerTag,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"excludes performer tag tagIdx2WithPerformer",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierExcludes,
|
|
Value: []string{strconv.Itoa(tagIDs[tagIdx2WithPerformer])},
|
|
},
|
|
},
|
|
nil,
|
|
[]int{galleryIdxWithTwoPerformerTag},
|
|
false,
|
|
},
|
|
{
|
|
"excludes sub-tags",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdxWithParentAndChild]),
|
|
},
|
|
Depth: &allDepth,
|
|
Modifier: models.CriterionModifierExcludes,
|
|
},
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformer,
|
|
galleryIdxWithPerformerTag,
|
|
galleryIdxWithPerformerTwoTags,
|
|
galleryIdxWithTwoPerformerTag,
|
|
},
|
|
[]int{
|
|
galleryIdxWithPerformerParentTag,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"is null",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierIsNull,
|
|
},
|
|
},
|
|
[]int{galleryIdx1WithImage},
|
|
[]int{galleryIdxWithPerformerTag},
|
|
false,
|
|
},
|
|
{
|
|
"not null",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotNull,
|
|
},
|
|
},
|
|
[]int{galleryIdxWithPerformerTag},
|
|
[]int{galleryIdx1WithImage},
|
|
false,
|
|
},
|
|
{
|
|
"equals",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx2WithPerformer]),
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
nil,
|
|
true,
|
|
},
|
|
{
|
|
"not equals",
|
|
nil,
|
|
&models.GalleryFilterType{
|
|
PerformerTags: &models.HierarchicalMultiCriterionInput{
|
|
Modifier: models.CriterionModifierNotEquals,
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx2WithPerformer]),
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
nil,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
results, _, err := db.Gallery.Query(ctx, tt.filter, tt.findFilter)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("ImageStore.Query() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
ids := galleriesToIDs(results)
|
|
|
|
include := indexesToIDs(galleryIDs, tt.includeIdxs)
|
|
exclude := indexesToIDs(galleryIDs, tt.excludeIdxs)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryTagCount(t *testing.T) {
|
|
const tagCount = 1
|
|
tagCountCriterion := models.IntCriterionInput{
|
|
Value: tagCount,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
verifyGalleriesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyGalleriesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierGreaterThan
|
|
verifyGalleriesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierLessThan
|
|
verifyGalleriesTagCount(t, tagCountCriterion)
|
|
}
|
|
|
|
func verifyGalleriesTagCount(t *testing.T, tagCountCriterion models.IntCriterionInput) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
galleryFilter := models.GalleryFilterType{
|
|
TagCount: &tagCountCriterion,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Greater(t, len(galleries), 0)
|
|
|
|
for _, gallery := range galleries {
|
|
if err := gallery.LoadTagIDs(ctx, sqb); err != nil {
|
|
t.Errorf("gallery.LoadTagIDs() error = %v", err)
|
|
return nil
|
|
}
|
|
verifyInt(t, len(gallery.TagIDs.List()), tagCountCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryPerformerCount(t *testing.T) {
|
|
const performerCount = 1
|
|
performerCountCriterion := models.IntCriterionInput{
|
|
Value: performerCount,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
verifyGalleriesPerformerCount(t, performerCountCriterion)
|
|
|
|
performerCountCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyGalleriesPerformerCount(t, performerCountCriterion)
|
|
|
|
performerCountCriterion.Modifier = models.CriterionModifierGreaterThan
|
|
verifyGalleriesPerformerCount(t, performerCountCriterion)
|
|
|
|
performerCountCriterion.Modifier = models.CriterionModifierLessThan
|
|
verifyGalleriesPerformerCount(t, performerCountCriterion)
|
|
}
|
|
|
|
func verifyGalleriesPerformerCount(t *testing.T, performerCountCriterion models.IntCriterionInput) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
galleryFilter := models.GalleryFilterType{
|
|
PerformerCount: &performerCountCriterion,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Greater(t, len(galleries), 0)
|
|
|
|
for _, gallery := range galleries {
|
|
if err := gallery.LoadPerformerIDs(ctx, sqb); err != nil {
|
|
t.Errorf("gallery.LoadPerformerIDs() error = %v", err)
|
|
return nil
|
|
}
|
|
|
|
verifyInt(t, len(gallery.PerformerIDs.List()), performerCountCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryAverageResolution(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
qb := db.Gallery
|
|
resolution := models.ResolutionEnumLow
|
|
galleryFilter := models.GalleryFilterType{
|
|
AverageResolution: &models.ResolutionCriterionInput{
|
|
Value: resolution,
|
|
Modifier: models.CriterionModifierEquals,
|
|
},
|
|
}
|
|
|
|
// not verifying average - just ensure we get at least one
|
|
galleries := queryGallery(ctx, t, qb, &galleryFilter, nil)
|
|
assert.Greater(t, len(galleries), 0)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQueryImageCount(t *testing.T) {
|
|
const imageCount = 0
|
|
imageCountCriterion := models.IntCriterionInput{
|
|
Value: imageCount,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
verifyGalleriesImageCount(t, imageCountCriterion)
|
|
|
|
imageCountCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyGalleriesImageCount(t, imageCountCriterion)
|
|
|
|
imageCountCriterion.Modifier = models.CriterionModifierGreaterThan
|
|
verifyGalleriesImageCount(t, imageCountCriterion)
|
|
|
|
imageCountCriterion.Modifier = models.CriterionModifierLessThan
|
|
verifyGalleriesImageCount(t, imageCountCriterion)
|
|
}
|
|
|
|
func verifyGalleriesImageCount(t *testing.T, imageCountCriterion models.IntCriterionInput) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
galleryFilter := models.GalleryFilterType{
|
|
ImageCount: &imageCountCriterion,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
|
|
assert.Greater(t, len(galleries), -1)
|
|
|
|
for _, gallery := range galleries {
|
|
pp := 0
|
|
|
|
result, err := db.Image.Query(ctx, models.ImageQueryOptions{
|
|
QueryOptions: models.QueryOptions{
|
|
FindFilter: &models.FindFilterType{
|
|
PerPage: &pp,
|
|
},
|
|
Count: true,
|
|
},
|
|
ImageFilter: &models.ImageFilterType{
|
|
Galleries: &models.MultiCriterionInput{
|
|
Value: []string{strconv.Itoa(gallery.ID)},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
verifyInt(t, result.Count, imageCountCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGalleryQuerySorting(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
sortBy string
|
|
dir models.SortDirectionEnum
|
|
firstGalleryIdx int // -1 to ignore
|
|
lastGalleryIdx int
|
|
}{
|
|
{
|
|
"file mod time",
|
|
"file_mod_time",
|
|
models.SortDirectionEnumDesc,
|
|
-1,
|
|
-1,
|
|
},
|
|
{
|
|
"path",
|
|
"path",
|
|
models.SortDirectionEnumDesc,
|
|
-1,
|
|
-1,
|
|
},
|
|
{
|
|
"title",
|
|
"title",
|
|
models.SortDirectionEnumDesc,
|
|
-1,
|
|
-1,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
got, _, err := qb.Query(ctx, nil, &models.FindFilterType{
|
|
Sort: &tt.sortBy,
|
|
Direction: &tt.dir,
|
|
})
|
|
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.TestGalleryQuerySorting() error = %v", err)
|
|
return
|
|
}
|
|
|
|
if !assert.Greater(len(got), 0) {
|
|
return
|
|
}
|
|
|
|
// scenes should be in same order as indexes
|
|
firstGallery := got[0]
|
|
lastGallery := got[len(got)-1]
|
|
|
|
if tt.firstGalleryIdx != -1 {
|
|
firstID := galleryIDs[tt.firstGalleryIdx]
|
|
assert.Equal(firstID, firstGallery.ID)
|
|
}
|
|
if tt.lastGalleryIdx != -1 {
|
|
lastID := galleryIDs[tt.lastGalleryIdx]
|
|
assert.Equal(lastID, lastGallery.ID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryStore_AddImages(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
galleryID int
|
|
imageIDs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"single",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{imageIDs[imageIdx1WithPerformer]},
|
|
false,
|
|
},
|
|
{
|
|
"multiple",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{imageIDs[imageIdx1WithPerformer], imageIDs[imageIdx1WithStudio]},
|
|
false,
|
|
},
|
|
{
|
|
"invalid gallery id",
|
|
invalidID,
|
|
[]int{imageIDs[imageIdx1WithPerformer]},
|
|
true,
|
|
},
|
|
{
|
|
"single invalid",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{invalidID},
|
|
true,
|
|
},
|
|
{
|
|
"one invalid",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{imageIDs[imageIdx1WithPerformer], invalidID},
|
|
true,
|
|
},
|
|
{
|
|
"existing",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{imageIDs[imageIdxWithGallery]},
|
|
false,
|
|
},
|
|
{
|
|
"one new",
|
|
galleryIDs[galleryIdx1WithImage],
|
|
[]int{imageIDs[imageIdx1WithPerformer], imageIDs[imageIdxWithGallery]},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
if err := qb.AddImages(ctx, tt.galleryID, tt.imageIDs...); (err != nil) != tt.wantErr {
|
|
t.Errorf("GalleryStore.AddImages() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
// ensure image was added
|
|
imageIDs, err := qb.GetImageIDs(ctx, tt.galleryID)
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.GetImageIDs() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert := assert.New(t)
|
|
for _, wantedID := range tt.imageIDs {
|
|
assert.Contains(imageIDs, wantedID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryStore_RemoveImages(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
galleryID int
|
|
imageIDs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"single",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{imageIDs[imageIdx1WithGallery]},
|
|
false,
|
|
},
|
|
{
|
|
"multiple",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{imageIDs[imageIdx1WithGallery], imageIDs[imageIdx2WithGallery]},
|
|
false,
|
|
},
|
|
{
|
|
"invalid gallery id",
|
|
invalidID,
|
|
[]int{imageIDs[imageIdx1WithGallery]},
|
|
false,
|
|
},
|
|
{
|
|
"single invalid",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{invalidID},
|
|
false,
|
|
},
|
|
{
|
|
"one invalid",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{imageIDs[imageIdx1WithGallery], invalidID},
|
|
false,
|
|
},
|
|
{
|
|
"not existing",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{imageIDs[imageIdxWithPerformer]},
|
|
false,
|
|
},
|
|
{
|
|
"one existing",
|
|
galleryIDs[galleryIdxWithTwoImages],
|
|
[]int{imageIDs[imageIdx1WithPerformer], imageIDs[imageIdx1WithGallery]},
|
|
false,
|
|
},
|
|
}
|
|
|
|
qb := db.Gallery
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
if err := qb.RemoveImages(ctx, tt.galleryID, tt.imageIDs...); (err != nil) != tt.wantErr {
|
|
t.Errorf("GalleryStore.RemoveImages() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
// ensure image was removed
|
|
imageIDs, err := qb.GetImageIDs(ctx, tt.galleryID)
|
|
if err != nil {
|
|
t.Errorf("GalleryStore.GetImageIDs() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert := assert.New(t)
|
|
for _, excludedID := range tt.imageIDs {
|
|
assert.NotContains(imageIDs, excludedID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGalleryQueryHasChapters(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
hasChapters := "true"
|
|
galleryFilter := models.GalleryFilterType{
|
|
HasChapters: &hasChapters,
|
|
}
|
|
|
|
q := getGalleryStringValue(galleryIdxWithChapters, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
galleries := queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.Len(t, galleries, 1)
|
|
assert.Equal(t, galleryIDs[galleryIdxWithChapters], galleries[0].ID)
|
|
|
|
hasChapters = "false"
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
assert.Len(t, galleries, 0)
|
|
|
|
findFilter.Q = nil
|
|
galleries = queryGallery(ctx, t, sqb, &galleryFilter, &findFilter)
|
|
|
|
assert.NotEqual(t, 0, len(galleries))
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGallerySetAndResetCover(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Gallery
|
|
|
|
imagePath2 := getFilePath(folderIdxWithImageFiles, getImageBasename(imageIdx2WithGallery))
|
|
|
|
result, err := db.Image.CoverByGalleryID(ctx, galleryIDs[galleryIdxWithTwoImages])
|
|
assert.Nil(t, err)
|
|
assert.Nil(t, result)
|
|
|
|
err = sqb.SetCover(ctx, galleryIDs[galleryIdxWithTwoImages], imageIDs[imageIdx2WithGallery])
|
|
assert.Nil(t, err)
|
|
|
|
result, err = db.Image.CoverByGalleryID(ctx, galleryIDs[galleryIdxWithTwoImages])
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, result.Path, imagePath2)
|
|
|
|
err = sqb.ResetCover(ctx, galleryIDs[galleryIdxWithTwoImages])
|
|
assert.Nil(t, err)
|
|
|
|
result, err = db.Image.CoverByGalleryID(ctx, galleryIDs[galleryIdxWithTwoImages])
|
|
assert.Nil(t, err)
|
|
assert.Nil(t, result)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// TODO Count
|
|
// TODO All
|
|
// TODO Query
|
|
// TODO Destroy
|