144 lines
4.0 KiB
Go
144 lines
4.0 KiB
Go
package assetloader
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestProcessEmbedDirectives_TextLiteralEscapesQuotes(t *testing.T) {
|
|
dir := t.TempDir()
|
|
sqlPath := filepath.Join(dir, "1_001_seed.sql")
|
|
if err := os.WriteFile(filepath.Join(dir, "body.txt"), []byte("Line 1\nIt's fine"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ProcessEmbedDirectives(sqlPath, `
|
|
-- @embed: path=body.txt var=:body mode=text
|
|
INSERT INTO notes (body) VALUES (:body);
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("ProcessEmbedDirectives failed: %v", err)
|
|
}
|
|
if !strings.Contains(got, "VALUES ('Line 1\nIt''s fine');") {
|
|
t.Fatalf("embedded SQL did not contain escaped text literal:\n%s", got)
|
|
}
|
|
if strings.Contains(got, "VALUES (:body);") {
|
|
t.Fatalf("placeholder was not replaced:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestProcessEmbedDirectives_Base64Literal(t *testing.T) {
|
|
dir := t.TempDir()
|
|
sqlPath := filepath.Join(dir, "1_001_seed.sql")
|
|
binary := []byte{0x00, 0xff, 0x10, 0x20}
|
|
if err := os.WriteFile(filepath.Join(dir, "blob.bin"), binary, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ProcessEmbedDirectives(sqlPath, `
|
|
-- @embed: path=blob.bin var=:payload mode=base64
|
|
INSERT INTO files (payload) VALUES (decode(:payload, 'base64')::bytea);
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("ProcessEmbedDirectives failed: %v", err)
|
|
}
|
|
want := "decode('" + base64.StdEncoding.EncodeToString(binary) + "', 'base64')::bytea"
|
|
if !strings.Contains(got, want) {
|
|
t.Fatalf("embedded SQL did not contain base64 literal %q:\n%s", want, got)
|
|
}
|
|
}
|
|
|
|
func TestProcessEmbedDirectives_RelativeToSQLFile(t *testing.T) {
|
|
root := t.TempDir()
|
|
sqlDir := filepath.Join(root, "nested", "seed")
|
|
if err := os.MkdirAll(filepath.Join(sqlDir, "assets"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlPath := filepath.Join(sqlDir, "1_001_seed.sql")
|
|
if err := os.WriteFile(filepath.Join(sqlDir, "assets", "body.txt"), []byte("relative body"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ProcessEmbedDirectives(sqlPath, `
|
|
-- @embed: path=assets/body.txt var=:body mode=text
|
|
SELECT :body;
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("ProcessEmbedDirectives failed: %v", err)
|
|
}
|
|
if !strings.Contains(got, "SELECT 'relative body';") {
|
|
t.Fatalf("path was not resolved relative to SQL file:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestProcessEmbedDirectives_InvalidDirectiveAndFiles(t *testing.T) {
|
|
dir := t.TempDir()
|
|
sqlPath := filepath.Join(dir, "1_001_seed.sql")
|
|
if err := os.WriteFile(filepath.Join(dir, "body.txt"), []byte("ok"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "binary.txt"), []byte{0xff, 0xfe}, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
sql string
|
|
}{
|
|
{
|
|
name: "missing mode",
|
|
sql: "-- @embed: path=body.txt var=:body\nSELECT :body;",
|
|
},
|
|
{
|
|
name: "invalid var",
|
|
sql: "-- @embed: path=body.txt var=body mode=text\nSELECT :body;",
|
|
},
|
|
{
|
|
name: "missing file",
|
|
sql: "-- @embed: path=missing.txt var=:body mode=text\nSELECT :body;",
|
|
},
|
|
{
|
|
name: "invalid utf8 text",
|
|
sql: "-- @embed: path=binary.txt var=:body mode=text\nSELECT :body;",
|
|
},
|
|
{
|
|
name: "placeholder not found",
|
|
sql: "-- @embed: path=body.txt var=:body mode=text\nSELECT 1;",
|
|
},
|
|
{
|
|
name: "unknown attribute",
|
|
sql: "-- @embed: path=body.txt var=:body mode=text extra=yes\nSELECT :body;",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if _, err := ProcessEmbedDirectives(sqlPath, tt.sql); err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProcessEmbedDirectives_DoesNotReplacePlaceholderPrefix(t *testing.T) {
|
|
dir := t.TempDir()
|
|
sqlPath := filepath.Join(dir, "1_001_seed.sql")
|
|
if err := os.WriteFile(filepath.Join(dir, "body.txt"), []byte("ok"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ProcessEmbedDirectives(sqlPath, `
|
|
-- @embed: path=body.txt var=:body mode=text
|
|
SELECT :body, :body_extra;
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("ProcessEmbedDirectives failed: %v", err)
|
|
}
|
|
if !strings.Contains(got, "SELECT 'ok', :body_extra;") {
|
|
t.Fatalf("placeholder boundary was not respected:\n%s", got)
|
|
}
|
|
}
|