Files
bamort/backend/pdfrender/pagination_test.go
T
2025-12-23 19:00:39 +01:00

941 lines
26 KiB
Go

package pdfrender
import (
"fmt"
"testing"
)
// Helper function to count non-empty skills (skills with a name)
func countNonEmptySkills(skills []SkillViewModel) int {
count := 0
for _, skill := range skills {
if skill.Name != "" {
count++
}
}
return count
}
// Helper function to count non-empty weapons
func countNonEmptyWeapons(weapons []WeaponViewModel) int {
count := 0
for _, weapon := range weapons {
if weapon.Name != "" {
count++
}
}
return count
}
// Helper function to count non-empty spells
func countNonEmptySpells(spells []SpellViewModel) int {
count := 0
for _, spell := range spells {
if spell.Name != "" {
count++
}
}
return count
}
// TestPaginateMultiList_SingleListType tests pagination with a single list type (skills only)
func TestPaginateMultiList_SingleListType(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create skills that will fit on one page (less than total capacity)
skills := make([]SkillViewModel, 20)
for i := 0; i < 20; i++ {
skills[i] = SkillViewModel{Name: fmt.Sprintf("Skill%d", i+1)}
}
dataMap := map[string]interface{}{
"skills": skills,
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_1.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(distributions) != 1 {
t.Fatalf("Expected 1 page, got %d", len(distributions))
}
// Verify data is distributed correctly
page := distributions[0]
if page.TemplateName != "page_1.html" {
t.Errorf("Expected template 'page_1.html', got '%s'", page.TemplateName)
}
// Check that skills are distributed to appropriate blocks
// Note: Skills are distributed to multiple columns, so we count each block
totalSkills := 0
skillBlocks := []string{"skills_column1", "skills_column2"}
for _, blockName := range skillBlocks {
if data, exists := page.Data[blockName]; exists {
if skillsList, ok := data.([]SkillViewModel); ok {
totalSkills += countNonEmptySkills(skillsList)
}
}
}
if totalSkills != 20 {
t.Errorf("Expected 20 total skills distributed across columns, got %d", totalSkills)
}
}
// TestPaginateMultiList_MultipleListTypes tests pagination with multiple list types
func TestPaginateMultiList_MultipleListTypes(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create skills and weapons for page_2.html
skills := make([]SkillViewModel, 30)
for i := 0; i < 30; i++ {
skills[i] = SkillViewModel{
Name: fmt.Sprintf("Skill%d", i+1),
IsLearned: i < 15, // First 15 are learned
Category: "Kampf",
}
}
weapons := make([]WeaponViewModel, 10)
for i := 0; i < 10; i++ {
weapons[i] = WeaponViewModel{
Name: fmt.Sprintf("Weapon%d", i+1),
Value: 10 + i,
}
}
dataMap := map[string]interface{}{
"skills": skills,
"weapons": weapons,
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_2.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(distributions) == 0 {
t.Fatal("Expected at least 1 page")
}
// Verify all data is distributed across pages
totalSkills := 0
totalWeapons := 0
for _, dist := range distributions {
for _, data := range dist.Data {
switch v := data.(type) {
case []SkillViewModel:
totalSkills += countNonEmptySkills(v)
case []WeaponViewModel:
totalWeapons += countNonEmptyWeapons(v)
}
}
}
if totalSkills != 30 {
t.Errorf("Expected 30 total skills, got %d", totalSkills)
}
if totalWeapons != 10 {
t.Errorf("Expected 10 total weapons, got %d", totalWeapons)
}
}
// TestPaginateMultiList_WithOverflow tests continuation pages are created
func TestPaginateMultiList_WithOverflow(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create many skills to force continuation pages
skills := make([]SkillViewModel, 100)
for i := 0; i < 100; i++ {
skills[i] = SkillViewModel{Name: fmt.Sprintf("Skill%d", i+1)}
}
dataMap := map[string]interface{}{
"skills": skills,
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_1.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(distributions) <= 1 {
t.Fatalf("Expected multiple pages for 100 skills, got %d", len(distributions))
}
// Verify continuation template naming
if distributions[0].TemplateName != "page_1.html" {
t.Errorf("First page should use base template, got '%s'", distributions[0].TemplateName)
}
for i := 1; i < len(distributions); i++ {
expectedName := "page_1.2.html"
if distributions[i].TemplateName != expectedName {
t.Errorf("Page %d should use continuation template '%s', got '%s'",
i+1, expectedName, distributions[i].TemplateName)
}
}
// Verify all skills are distributed
totalSkills := 0
for _, dist := range distributions {
for blockName, data := range dist.Data {
// Only count skill blocks to avoid counting the same skills multiple times
if skillsList, ok := data.([]SkillViewModel); ok &&
(blockName == "skills_column1" || blockName == "skills_column2" ||
blockName == "skills_column3" || blockName == "skills_column4") {
totalSkills += countNonEmptySkills(skillsList)
}
}
}
if totalSkills != 100 {
t.Errorf("Expected 100 total skills distributed, got %d", totalSkills)
}
}
// TestPaginateMultiList_EmptyLists tests handling of empty data
func TestPaginateMultiList_EmptyLists(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
dataMap := map[string]interface{}{
"skills": []SkillViewModel{},
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_1.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(distributions) != 0 {
t.Errorf("Expected 0 pages for empty data, got %d", len(distributions))
}
}
// TestPaginateMultiList_WithFilters tests filtering by learned/unlearned/language
func TestPaginateMultiList_WithFilters(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create mixed skills
skills := []SkillViewModel{
{Name: "Learned1", IsLearned: true, Category: "Kampf"},
{Name: "Learned2", IsLearned: true, Category: "Körper"},
{Name: "Unlearned1", IsLearned: false, Category: "Kampf"},
{Name: "Unlearned2", IsLearned: false, Category: "Social"},
{Name: "Language1", Category: "Sprache"},
{Name: "Language2", Category: "Sprache"},
}
dataMap := map[string]interface{}{
"skills": skills,
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_2.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(distributions) == 0 {
t.Fatal("Expected at least 1 page")
}
// Verify filtering worked - check that learned, unlearned, and language skills are in separate blocks
page := distributions[0]
if learnedData, ok := page.Data["skills_learned"]; ok {
learned := learnedData.([]SkillViewModel)
for _, skill := range learned {
// Skip empty items (padding)
if skill.Name == "" {
continue
}
if !skill.IsLearned {
t.Errorf("Found unlearned skill '%s' in learned block", skill.Name)
}
}
}
if languageData, ok := page.Data["skills_languages"]; ok {
languages := languageData.([]SkillViewModel)
for _, skill := range languages {
// Skip empty items (padding)
if skill.Name == "" {
continue
}
if skill.Category != "Sprache" {
t.Errorf("Found non-language skill '%s' in language block", skill.Name)
}
}
}
}
// TestPaginateMultiList_UnknownTemplate tests error handling for unknown templates
func TestPaginateMultiList_UnknownTemplate(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
dataMap := map[string]interface{}{
"skills": []SkillViewModel{{Name: "Test"}},
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "nonexistent_template.html")
// Assert
if err == nil {
t.Fatal("Expected error for unknown template, got nil")
}
if distributions != nil {
t.Error("Expected nil distributions for error case")
}
}
// TestPaginateMultiList_PageNumbering tests that page numbers are sequential
func TestPaginateMultiList_PageNumbering(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create enough skills for 3 pages
skills := make([]SkillViewModel, 120)
for i := 0; i < 120; i++ {
skills[i] = SkillViewModel{Name: fmt.Sprintf("Skill%d", i+1)}
}
dataMap := map[string]interface{}{
"skills": skills,
}
// Act
distributions, err := paginator.PaginateMultiList(dataMap, "page_1.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Verify page numbers are sequential
for i, dist := range distributions {
expectedPageNum := i + 1
if dist.PageNumber != expectedPageNum {
t.Errorf("Page %d has incorrect PageNumber: expected %d, got %d",
i+1, expectedPageNum, dist.PageNumber)
}
}
}
func TestSliceList_Basic(t *testing.T) {
// Arrange
items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Act
result, hasMore := SliceList(items, 0, 5)
// Assert
if len(result) != 5 {
t.Errorf("Expected 5 items, got %d", len(result))
}
if !hasMore {
t.Error("Expected hasMore to be true")
}
if result[0] != 1 || result[4] != 5 {
t.Error("Unexpected slice content")
}
}
func TestSliceList_LastPage(t *testing.T) {
// Arrange
items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Act
result, hasMore := SliceList(items, 5, 10)
// Assert
if len(result) != 5 {
t.Errorf("Expected 5 items, got %d", len(result))
}
if hasMore {
t.Error("Expected hasMore to be false")
}
}
func TestSliceList_BeyondEnd(t *testing.T) {
// Arrange
items := []int{1, 2, 3}
// Act
result, hasMore := SliceList(items, 10, 5)
// Assert
if len(result) != 0 {
t.Errorf("Expected 0 items, got %d", len(result))
}
if hasMore {
t.Error("Expected hasMore to be false")
}
}
func TestPaginateSkills_SinglePage(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get column capacities from template
var col1Capacity int
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == "page_1.html" {
for _, block := range tmpl.Metadata.Blocks {
if block.Name == "skills_column1" {
col1Capacity = block.MaxItems
break
}
}
break
}
}
// Create skills that fit within first column only
numSkills := col1Capacity
skills := make([]SkillViewModel, numSkills)
for i := 0; i < numSkills; i++ {
skills[i] = SkillViewModel{Name: "Skill" + string(rune('A'+i))}
}
// Act
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(pages) != 1 {
t.Fatalf("Expected 1 page, got %d", len(pages))
}
// Check that data is distributed across columns
page := pages[0]
if page.PageNumber != 1 {
t.Errorf("Expected page number 1, got %d", page.PageNumber)
}
// Column 1 should have all skills (exactly matching capacity)
col1Data, ok := page.Data["skills_column1"].([]SkillViewModel)
if !ok {
t.Fatal("skills_column1 data not found or wrong type")
}
if len(col1Data) != numSkills {
t.Errorf("Expected %d skills in column 1 (capacity), got %d", numSkills, len(col1Data))
}
// Column 2 should be empty (no overflow)
col2Data, ok := page.Data["skills_column2"].([]SkillViewModel)
if !ok {
t.Fatal("skills_column2 data not found or wrong type")
}
if len(col2Data) != 0 {
t.Errorf("Expected 0 skills in column 2, got %d", len(col2Data))
}
}
func TestPaginateSkills_MultiColumn(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get expected capacity from template
var page1Template *TemplateWithMeta
for i := range templateSet.Templates {
if templateSet.Templates[i].Metadata.Name == "page_1.html" {
page1Template = &templateSet.Templates[i]
break
}
}
col1Block := GetBlockByName(page1Template.Metadata.Blocks, "skills_column1")
col2Block := GetBlockByName(page1Template.Metadata.Blocks, "skills_column2")
totalCapacity := col1Block.MaxItems + col2Block.MaxItems
// Create enough skills to use both columns but fit on one page
// Use totalCapacity - 1 to test partial fill of second column
numSkills := col1Block.MaxItems + 2
if numSkills > totalCapacity {
numSkills = totalCapacity
}
skills := make([]SkillViewModel, numSkills)
for i := 0; i < numSkills; i++ {
skills[i] = SkillViewModel{Name: "Skill" + string(rune(i))}
}
// Act
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Should fit on one page
expectedPages := (numSkills + totalCapacity - 1) / totalCapacity
if len(pages) != expectedPages {
t.Fatalf("Expected %d page, got %d", expectedPages, len(pages))
}
page := pages[0]
// Column 1 should have max capacity skills from template
col1Data := page.Data["skills_column1"].([]SkillViewModel)
if len(col1Data) != col1Block.MaxItems {
t.Errorf("Expected %d skills in column 1 (from template), got %d", col1Block.MaxItems, len(col1Data))
}
// Column 2 should have remaining skills
col2Data := page.Data["skills_column2"].([]SkillViewModel)
expectedCol2 := numSkills - col1Block.MaxItems
if len(col2Data) != expectedCol2 {
t.Errorf("Expected %d skills in column 2 (%d total - %d in col1), got %d", expectedCol2, numSkills, col1Block.MaxItems, len(col2Data))
}
}
func TestPaginateSkills_MultiPage(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get column capacities from template
var page1Template *TemplateWithMeta
for i := range templateSet.Templates {
if templateSet.Templates[i].Metadata.Name == "page_1.html" {
page1Template = &templateSet.Templates[i]
break
}
}
col1Block := GetBlockByName(page1Template.Metadata.Blocks, "skills_column1")
col2Block := GetBlockByName(page1Template.Metadata.Blocks, "skills_column2")
totalCapacity := col1Block.MaxItems + col2Block.MaxItems
// Create enough skills to span exactly 2 pages
numSkills := totalCapacity + 1
skills := make([]SkillViewModel, numSkills)
for i := 0; i < numSkills; i++ {
skills[i] = SkillViewModel{Name: "Skill" + string(rune(i))}
}
// Act
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
expectedPages := 2
if len(pages) != expectedPages {
t.Fatalf("Expected %d pages, got %d", expectedPages, len(pages))
}
// Page 1 should have full capacity (col1 + col2)
page1 := pages[0]
col1Page1 := page1.Data["skills_column1"].([]SkillViewModel)
col2Page1 := page1.Data["skills_column2"].([]SkillViewModel)
if len(col1Page1) != col1Block.MaxItems {
t.Errorf("Page 1 col1: expected %d skills (template capacity), got %d", col1Block.MaxItems, len(col1Page1))
}
if len(col2Page1) != col2Block.MaxItems {
t.Errorf("Page 1 col2: expected %d skills (template capacity), got %d", col2Block.MaxItems, len(col2Page1))
}
// Page 2 should have remaining skills (just 1 skill)
page2 := pages[1]
col1Page2 := page2.Data["skills_column1"].([]SkillViewModel)
col2Page2 := page2.Data["skills_column2"].([]SkillViewModel)
remainingSkills := numSkills - totalCapacity
if len(col1Page2) != remainingSkills {
t.Errorf("Page 2 col1: expected %d skills (remaining), got %d", remainingSkills, len(col1Page2))
}
if len(col2Page2) != 0 {
t.Errorf("Page 2 col2: expected 0 skills, got %d", len(col2Page2))
}
}
func TestPaginateSpells_TwoColumns(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get spell column capacities from template
var page3Template *TemplateWithMeta
for i := range templateSet.Templates {
if templateSet.Templates[i].Metadata.Name == "page_3.html" {
page3Template = &templateSet.Templates[i]
break
}
}
var leftCapacity, rightCapacity int
for i := range page3Template.Metadata.Blocks {
if page3Template.Metadata.Blocks[i].Name == "spells_column1" {
leftCapacity = page3Template.Metadata.Blocks[i].MaxItems
} else if page3Template.Metadata.Blocks[i].Name == "spells_column2" {
rightCapacity = page3Template.Metadata.Blocks[i].MaxItems
}
}
totalCapacity := leftCapacity + rightCapacity
// Create spells that fit within total capacity
testCount := totalCapacity
if testCount > 0 {
spells := make([]SpellViewModel, testCount)
for i := 0; i < testCount; i++ {
spells[i] = SpellViewModel{Name: "Spell" + string(rune('A'+i))}
}
// Act
pages, err := paginator.PaginateSpells(spells, "page_3.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(pages) != 1 {
t.Fatalf("Expected 1 page (capacity %d from template), got %d", totalCapacity, len(pages))
}
page := pages[0]
// Left column should be filled first
leftData := page.Data["spells_column1"].([]SpellViewModel)
expectedLeft := leftCapacity
if testCount < leftCapacity {
expectedLeft = testCount
}
if len(leftData) != expectedLeft {
t.Errorf("Expected %d spells in left column (template capacity), got %d", expectedLeft, len(leftData))
}
// Right column gets remainder
rightData := page.Data["spells_column2"].([]SpellViewModel)
expectedRight := testCount - expectedLeft
if len(rightData) != expectedRight {
t.Errorf("Expected %d spells in right column (remaining), got %d", expectedRight, len(rightData))
}
}
}
func TestPaginateSpells_MultiPage(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get spell column capacities from template
var page3Template *TemplateWithMeta
for i := range templateSet.Templates {
if templateSet.Templates[i].Metadata.Name == "page_3.html" {
page3Template = &templateSet.Templates[i]
break
}
}
var leftCapacity, rightCapacity int
for i := range page3Template.Metadata.Blocks {
if page3Template.Metadata.Blocks[i].Name == "spells_column1" {
leftCapacity = page3Template.Metadata.Blocks[i].MaxItems
} else if page3Template.Metadata.Blocks[i].Name == "spells_column2" {
rightCapacity = page3Template.Metadata.Blocks[i].MaxItems
}
}
// Create 30 spells - should span multiple pages based on template capacity
spells := make([]SpellViewModel, 30)
for i := 0; i < 30; i++ {
spells[i] = SpellViewModel{Name: "Spell" + string(rune(i))}
}
// Act
pages, err := paginator.PaginateSpells(spells, "page_3.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// With capacity from template, 30 spells require 2 pages
totalCapacity := leftCapacity + rightCapacity
expectedPages := (30 + totalCapacity - 1) / totalCapacity // ceiling division
if len(pages) != expectedPages {
t.Fatalf("Expected %d pages (capacity %d from template), got %d", expectedPages, totalCapacity, len(pages))
}
// Page 1 should have full capacity (left + right)
page1 := pages[0]
leftPage1 := page1.Data["spells_column1"].([]SpellViewModel)
rightPage1 := page1.Data["spells_column2"].([]SpellViewModel)
if len(leftPage1) != leftCapacity {
t.Errorf("Page 1 left: expected %d spells (template capacity), got %d", leftCapacity, len(leftPage1))
}
if len(rightPage1) != rightCapacity {
t.Errorf("Page 1 right: expected %d spells (template capacity), got %d", rightCapacity, len(rightPage1))
}
}
func TestPaginateWeapons_SinglePage(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get weapon capacity from template
var weaponCapacity int
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == "page_2.html" {
for _, block := range tmpl.Metadata.Blocks {
if block.ListType == "weapons" {
weaponCapacity = block.MaxItems
break
}
}
break
}
}
// Create fewer weapons than capacity
numWeapons := weaponCapacity - 2
if numWeapons < 1 {
numWeapons = 1
}
weapons := make([]WeaponViewModel, numWeapons)
for i := 0; i < numWeapons; i++ {
weapons[i] = WeaponViewModel{Name: "Weapon" + string(rune('A'+i))}
}
// Act
pages, err := paginator.PaginateWeapons(weapons, "page_2.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
expectedPages := 1
if len(pages) != expectedPages {
t.Fatalf("Expected %d page (capacity %d, items %d), got %d", expectedPages, weaponCapacity, numWeapons, len(pages))
}
page := pages[0]
weaponsData := page.Data["weapons_main"].([]WeaponViewModel)
if len(weaponsData) != numWeapons {
t.Errorf("Expected %d weapons, got %d", numWeapons, len(weaponsData))
}
}
func TestPaginateWeapons_MultiPage(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get weapon capacity from template
var page2Template *TemplateWithMeta
for i := range templateSet.Templates {
if templateSet.Templates[i].Metadata.Name == "page_2.html" {
page2Template = &templateSet.Templates[i]
break
}
}
if page2Template == nil {
t.Fatal("page_2.html template not found")
}
var weaponsBlock *BlockMetadata
for i := range page2Template.Metadata.Blocks {
if page2Template.Metadata.Blocks[i].Name == "weapons_main" {
weaponsBlock = &page2Template.Metadata.Blocks[i]
break
}
}
if weaponsBlock == nil {
t.Fatal("weapons_main block not found")
}
weaponCapacity := weaponsBlock.MaxItems
// Create 50 weapons - should span 3 pages based on template capacity
weapons := make([]WeaponViewModel, 50)
for i := 0; i < 50; i++ {
weapons[i] = WeaponViewModel{Name: "Weapon" + string(rune(i))}
}
// Act
pages, err := paginator.PaginateWeapons(weapons, "page_2.html")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
expectedPages := (50 + weaponCapacity - 1) / weaponCapacity // ceiling division
if len(pages) != expectedPages {
t.Fatalf("Expected %d pages (%d capacity from template), got %d", expectedPages, weaponCapacity, len(pages))
}
// First pages should have weaponCapacity weapons each
for i := 0; i < expectedPages-1; i++ {
pageWeapons := pages[i].Data["weapons_main"].([]WeaponViewModel)
if len(pageWeapons) != weaponCapacity {
t.Errorf("Page %d: expected %d weapons (template capacity), got %d", i+1, weaponCapacity, len(pageWeapons))
}
}
// Last page should have remaining weapons
remainingWeapons := 50 - ((expectedPages - 1) * weaponCapacity)
lastPageWeapons := pages[expectedPages-1].Data["weapons_main"].([]WeaponViewModel)
if len(lastPageWeapons) != remainingWeapons {
t.Errorf("Last page: expected %d weapons (remaining), got %d", remainingWeapons, len(lastPageWeapons))
}
}
func TestCalculatePagesNeeded(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Get capacities from templates
var page1Template, page2Template, page3Template *TemplateWithMeta
for i := range templateSet.Templates {
switch templateSet.Templates[i].Metadata.Name {
case "page_1.html":
page1Template = &templateSet.Templates[i]
case "page_2.html":
page2Template = &templateSet.Templates[i]
case "page_3.html":
page3Template = &templateSet.Templates[i]
}
}
// Get skill capacity (col1 + col2)
var skillCol1, skillCol2 int
for i := range page1Template.Metadata.Blocks {
if page1Template.Metadata.Blocks[i].Name == "skills_column1" {
skillCol1 = page1Template.Metadata.Blocks[i].MaxItems
} else if page1Template.Metadata.Blocks[i].Name == "skills_column2" {
skillCol2 = page1Template.Metadata.Blocks[i].MaxItems
}
}
skillCapacity := skillCol1 + skillCol2
// Get weapon capacity
var weaponCapacity int
for i := range page2Template.Metadata.Blocks {
if page2Template.Metadata.Blocks[i].Name == "weapons_main" {
weaponCapacity = page2Template.Metadata.Blocks[i].MaxItems
break
}
}
// Get spell capacity (col1 + col2)
var spellCol1, spellCol2 int
for i := range page3Template.Metadata.Blocks {
if page3Template.Metadata.Blocks[i].Name == "spells_column1" {
spellCol1 = page3Template.Metadata.Blocks[i].MaxItems
} else if page3Template.Metadata.Blocks[i].Name == "spells_column2" {
spellCol2 = page3Template.Metadata.Blocks[i].MaxItems
}
}
spellCapacity := spellCol1 + spellCol2
testCases := []struct {
name string
templateName string
listType string
itemCount int
expectedPages int
}{
{"10 skills on page1", "page_1.html", "skills", 10, 1},
{fmt.Sprintf("%d skills on page1", skillCapacity), "page_1.html", "skills", skillCapacity, 1},
{fmt.Sprintf("%d skills on page1", skillCapacity+1), "page_1.html", "skills", skillCapacity + 1, 2},
{"100 skills on page1", "page_1.html", "skills", 100, (100 + skillCapacity - 1) / skillCapacity}, // Dynamic calculation
{"10 weapons on page2", "page_2.html", "weapons", 10, (10 + weaponCapacity - 1) / weaponCapacity}, // Dynamic calculation
{fmt.Sprintf("%d weapons on page2", weaponCapacity), "page_2.html", "weapons", weaponCapacity, 1},
{fmt.Sprintf("%d weapons on page2", weaponCapacity+1), "page_2.html", "weapons", weaponCapacity + 1, 2},
{"10 spells on page3", "page_3.html", "spells", 10, (10 + spellCapacity - 1) / spellCapacity}, // Dynamic calculation
{fmt.Sprintf("%d spells on page3", spellCapacity), "page_3.html", "spells", spellCapacity, 1},
{fmt.Sprintf("%d spells on page3", spellCapacity+1), "page_3.html", "spells", spellCapacity + 1, 2},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Act
pages, err := paginator.CalculatePagesNeeded(tc.templateName, tc.listType, tc.itemCount)
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if pages != tc.expectedPages {
t.Errorf("Expected %d pages, got %d", tc.expectedPages, pages)
}
})
}
}
func TestPaginateSkills_EmptyList(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
skills := []SkillViewModel{}
// Act
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(pages) != 0 {
t.Errorf("Expected 0 pages for empty list, got %d", len(pages))
}
}
func TestPaginateSkills_InvalidTemplate(t *testing.T) {
// Arrange
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
skills := []SkillViewModel{{Name: "Test"}}
// Act
_, err := paginator.PaginateSkills(skills, "nonexistent.html", "")
// Assert
if err == nil {
t.Error("Expected error for invalid template, got nil")
}
}