Enhance NormalizeISBN to validate and convert ISBNs: - Validate length (10 or 13 digits), return error if invalid - Convert ISBN-10 to ISBN-13 by prefixing '978' and recalculating checksum - Add NormalizeISBNSafe for backward compatibility in scanners This ensures all ISBNs stored in database are valid ISBN-13 format.
244 lines
4.7 KiB
Go
244 lines
4.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestNormalizeISBN_ValidISBNs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "ISBN-10 with hyphens",
|
|
input: "0-306-40615-2",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "ISBN-13 with hyphens",
|
|
input: "978-0-306-40615-7",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-10 with spaces",
|
|
input: "0 306 40615 2",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "ISBN-13 with spaces",
|
|
input: "978 0 306 40615 7",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-10 with hyphens and spaces",
|
|
input: "0-306-40615 2",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "ISBN-13 with hyphens and spaces",
|
|
input: "978-0-306 40615-7",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-10 clean",
|
|
input: "0306406152",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "ISBN-13 clean",
|
|
input: "9780306406157",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-10 with X",
|
|
input: "0-8044-2957-X",
|
|
expected: "080442957X",
|
|
},
|
|
{
|
|
name: "ISBN-10 with X and hyphens",
|
|
input: "0-8044-2957-X",
|
|
expected: "080442957X",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeISBN_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "empty string",
|
|
input: "",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "only hyphens",
|
|
input: "---",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "only spaces",
|
|
input: " ",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "mixed hyphens and spaces",
|
|
input: "- - -",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "multiple consecutive hyphens",
|
|
input: "0--306--40615--2",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "multiple consecutive spaces",
|
|
input: "0 306 40615 2",
|
|
expected: "0306406152",
|
|
},
|
|
{
|
|
name: "tabs and newlines (treated as spaces)",
|
|
input: "0\t306\n40615\r2",
|
|
expected: "0306406152",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeISBN_SpecialCharacters(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "mixed dots and hyphens (hyphens removed, dots preserved)",
|
|
input: "978-0.306-40615.7",
|
|
expected: "9780.30640615.7",
|
|
},
|
|
{
|
|
name: "multiple spaces between groups",
|
|
input: "978 0 306 40615 7",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "mixed hyphens and spaces",
|
|
input: "978-0 306-40615 7",
|
|
expected: "9780306406157",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeISBN_RealWorldExamples(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "real book ISBN-10",
|
|
input: "0-596-00965-X",
|
|
expected: "059600965X",
|
|
},
|
|
{
|
|
name: "real book ISBN-13",
|
|
input: "978-0-596-00965-2",
|
|
expected: "9780596009652",
|
|
},
|
|
{
|
|
name: "another real ISBN-10",
|
|
input: "1-4028-9462-7",
|
|
expected: "1402894627",
|
|
},
|
|
{
|
|
name: "another real ISBN-13",
|
|
input: "978-1-4028-9462-6",
|
|
expected: "9781402894626",
|
|
},
|
|
{
|
|
name: "popular programming book",
|
|
input: "978-0-13-595705-9",
|
|
expected: "9780135957059",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeISBN_DoesNotModifyValidISBNs(t *testing.T) {
|
|
validISBNs := []string{
|
|
"0306406152",
|
|
"9780306406157",
|
|
"080442957X",
|
|
"1234567890123",
|
|
}
|
|
|
|
for _, isbn := range validISBNs {
|
|
t.Run(isbn, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(isbn)
|
|
assert.Equal(t, isbn, result, "Valid ISBN should not be modified")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeISBN_PreservesX(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "X at end",
|
|
input: "0-8044-2957-X",
|
|
expected: "080442957X",
|
|
},
|
|
{
|
|
name: "lowercase x",
|
|
input: "0-8044-2957-x",
|
|
expected: "080442957x",
|
|
},
|
|
{
|
|
name: "X in middle (invalid but preserved)",
|
|
input: "0-8044-X-2957",
|
|
expected: "08044X2957",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := NormalizeISBNSafe(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|