Files
xuanzhi-service/server/service/book/validation_test.go

131 lines
4.7 KiB
Go

package book
import (
"reflect"
"strings"
"testing"
"github.com/flipped-aurora/gin-vue-admin/server/model/book"
)
func TestValidateBookRejectsOutOfRangeAggregates(t *testing.T) {
tests := []struct {
name string
item book.Book
want string
}{
{name: "negative hot score", item: book.Book{HotScore: -1}, want: "hotScore"},
{name: "rating below zero", item: book.Book{Rating: -0.1}, want: "rating"},
{name: "rating above ten", item: book.Book{Rating: 10.1}, want: "rating"},
{name: "negative comment count", item: book.Book{CommentCount: -1}, want: "commentCount"},
{name: "negative word count", item: book.Book{WordCount: -1}, want: "wordCount"},
{name: "negative series sort", item: book.Book{SeriesSort: -1}, want: "seriesSort"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertValidationErrorContains(t, validateBook(tt.item), tt.want)
})
}
}
func TestValidateBookRejectsInvalidFixedDictionaryValues(t *testing.T) {
tests := []struct {
name string
item book.Book
want string
}{
{name: "invalid era tag", item: book.Book{EraTag: "bad", CompletionStatus: book.BookCompletionStatusSerializing, PublishStatus: book.BookPublishStatusDraft}, want: "eraTag"},
{name: "invalid completion status", item: book.Book{EraTag: book.BookEraTagUnknown, CompletionStatus: "bad", PublishStatus: book.BookPublishStatusDraft}, want: "completionStatus"},
{name: "invalid publish status", item: book.Book{EraTag: book.BookEraTagUnknown, CompletionStatus: book.BookCompletionStatusSerializing, PublishStatus: "bad"}, want: "publishStatus"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertValidationErrorContains(t, validateBook(tt.item), tt.want)
})
}
}
func TestBookAuthorUsesIsEnabledBooleanContract(t *testing.T) {
authorType := reflect.TypeOf(book.BookAuthor{})
legacyFieldName := "Author" + "Status"
if _, ok := authorType.FieldByName(legacyFieldName); ok {
t.Fatal("BookAuthor still exposes legacy status field, want IsEnabled boolean only")
}
field, ok := authorType.FieldByName("IsEnabled")
if !ok {
t.Fatal("BookAuthor missing IsEnabled field")
}
if field.Type.Kind() != reflect.Bool {
t.Fatalf("BookAuthor.IsEnabled kind = %s, want bool", field.Type.Kind())
}
if got := field.Tag.Get("json"); got != "isEnabled" {
t.Fatalf("BookAuthor.IsEnabled json tag = %q, want isEnabled", got)
}
}
func TestApplyBookAuthorRelationDefaults(t *testing.T) {
item := applyBookAuthorRelationDefaults(book.BookAuthorRelation{})
if item.AuthorSort != 1 {
t.Fatalf("AuthorSort = %d, want 1", item.AuthorSort)
}
}
func TestValidateBookChapterRejectsReadableWithoutLines(t *testing.T) {
err := validateBookChapter(book.BookChapter{ChapterNo: 1, IsReadable: true, TotalLines: 0})
assertValidationErrorContains(t, err, "totalLines")
}
func TestValidateBookAuthorRelationRejectsInvalidSort(t *testing.T) {
err := validateBookAuthorRelation(book.BookAuthorRelation{AuthorSort: 0})
assertValidationErrorContains(t, err, "authorSort")
}
func TestValidateBookCommentRejectsInvalidAnchorLikeCountAndStatus(t *testing.T) {
tests := []struct {
name string
item book.BookComment
want string
}{
{name: "book comment with line", item: book.BookComment{ChapterID: 0, LineIndex: 1}, want: "lineIndex"},
{name: "negative like count", item: book.BookComment{LikeCount: -1}, want: "likeCount"},
{name: "invalid comment status", item: book.BookComment{CommentStatus: "bad"}, want: "commentStatus"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertValidationErrorContains(t, validateBookComment(tt.item), tt.want)
})
}
}
func TestValidateBookReadRecordRejectsInvalidProgressAndAnchor(t *testing.T) {
tests := []struct {
name string
item book.BookReadRecord
want string
}{
{name: "progress below zero", item: book.BookReadRecord{ReadProgress: -0.1, ChapterID: 1, LineIndex: 1}, want: "readProgress"},
{name: "progress above one hundred", item: book.BookReadRecord{ReadProgress: 100.1, ChapterID: 1, LineIndex: 1}, want: "readProgress"},
{name: "missing chapter", item: book.BookReadRecord{ReadProgress: 10, ChapterID: 0, LineIndex: 1}, want: "chapterId"},
{name: "missing line", item: book.BookReadRecord{ReadProgress: 10, ChapterID: 1, LineIndex: 0}, want: "lineIndex"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertValidationErrorContains(t, validateBookReadRecord(tt.item), tt.want)
})
}
}
func assertValidationErrorContains(t *testing.T, err error, want string) {
t.Helper()
if err == nil {
t.Fatalf("validation error = nil, want %q", want)
}
if !strings.Contains(err.Error(), want) {
t.Fatalf("validation error = %q, want contains %q", err.Error(), want)
}
}