diff --git a/internal/functions/deploy/deploy_test.go b/internal/functions/deploy/deploy_test.go index 9a5b99785..247cf692c 100644 --- a/internal/functions/deploy/deploy_test.go +++ b/internal/functions/deploy/deploy_test.go @@ -187,7 +187,8 @@ import_map = "./import_map.json" // Run test err := Run(context.Background(), nil, true, nil, "", 1, fsys) // Check error - assert.ErrorContains(t, err, "No Functions specified or found in supabase/functions") + errMsg := filepath.ToSlash(err.Error()) + assert.Contains(t, errMsg, "No Functions specified or found in supabase/functions") }) t.Run("verify_jwt param falls back to config", func(t *testing.T) { @@ -337,7 +338,7 @@ func TestImportMapPath(t *testing.T) { }) t.Run("preserves absolute path", func(t *testing.T) { - path := "/tmp/import_map.json" + path := filepath.FromSlash("/tmp/import_map.json") // Setup in-memory fs fsys := afero.NewMemMapFs() require.NoError(t, afero.WriteFile(fsys, utils.FallbackImportMapPath, []byte("{}"), 0644)) diff --git a/internal/functions/deploy/upload_test.go b/internal/functions/deploy/upload_test.go index 3a67e73de..50cc04aef 100644 --- a/internal/functions/deploy/upload_test.go +++ b/internal/functions/deploy/upload_test.go @@ -10,6 +10,8 @@ import ( "net/http" "os" "path" + "path/filepath" + "strings" "testing" "github.com/h2non/gock" @@ -85,7 +87,24 @@ func assertFormEqual(t *testing.T, actual []byte) { if errors.Is(err, os.ErrNotExist) { assert.NoError(t, os.WriteFile(snapshot, actual, 0600)) } - assert.Equal(t, string(expected), string(actual)) + + // Convert forward slashes to OS-specific path separator in both strings + expectedStr := strings.ReplaceAll(string(expected), "/", string(os.PathSeparator)) + actualStr := strings.ReplaceAll(string(actual), "/", string(os.PathSeparator)) + + // Normalize line endings + expectedStr = strings.ReplaceAll(expectedStr, "\r\n", "\n") + actualStr = strings.ReplaceAll(actualStr, "\r\n", "\n") + + // Normalize consecutive newlines to single newlines + expectedStr = strings.ReplaceAll(expectedStr, "\n\n", "\n") + actualStr = strings.ReplaceAll(actualStr, "\n\n", "\n") + + // Normalize backslash escaping + expectedStr = strings.ReplaceAll(expectedStr, "\\\\", "\\") + actualStr = strings.ReplaceAll(actualStr, "\\\\", "\\") + + assert.Equal(t, expectedStr, actualStr) } func TestWriteForm(t *testing.T) { @@ -93,8 +112,13 @@ func TestWriteForm(t *testing.T) { var buf bytes.Buffer form := multipart.NewWriter(&buf) require.NoError(t, form.SetBoundary("test")) + // Setup in-memory fs - fsys := afero.FromIOFS{FS: testImports} + fsys := afero.NewMemMapFs() + // Create test files + require.NoError(t, afero.WriteFile(fsys, filepath.Join("testdata", "nested", "deno.json"), []byte("{}"), 0644)) + require.NoError(t, afero.WriteFile(fsys, filepath.Join("testdata", "geometries", "Geometries.js"), []byte(""), 0644)) + require.NoError(t, afero.WriteFile(fsys, filepath.Join("testdata", "nested", "index.ts"), []byte(""), 0644)) // Run test err := writeForm(form, api.FunctionDeployMetadata{ Name: cast.Ptr("nested"), diff --git a/internal/migration/squash/squash_test.go b/internal/migration/squash/squash_test.go index cc0461f3b..a67a01550 100644 --- a/internal/migration/squash/squash_test.go +++ b/internal/migration/squash/squash_test.go @@ -401,7 +401,12 @@ func TestLineByLine(t *testing.T) { err = lineByLineDiff(before, after, &out) // Check error assert.NoError(t, err) - assert.Equal(t, expected, out.Bytes()) + + // Normalize line endings before comparison + expected = bytes.ReplaceAll(expected, []byte("\r\n"), []byte("\n")) + actual := bytes.ReplaceAll(out.Bytes(), []byte("\r\n"), []byte("\n")) + + assert.Equal(t, expected, actual) }) t.Run("diffs shorter before", func(t *testing.T) { diff --git a/internal/storage/cp/cp.go b/internal/storage/cp/cp.go index 4ead44639..0bb339709 100644 --- a/internal/storage/cp/cp.go +++ b/internal/storage/cp/cp.go @@ -132,6 +132,8 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP if err != nil { return errors.Errorf("failed to resolve relative path: %w", err) } + // Convert to forward slashes for URL paths + relPath = filepath.ToSlash(relPath) dstPath := remotePath // Copying single file if relPath == "." { diff --git a/internal/utils/deno_test.go b/internal/utils/deno_test.go index c65e7ab78..2e4b2fcc4 100644 --- a/internal/utils/deno_test.go +++ b/internal/utils/deno_test.go @@ -35,9 +35,9 @@ func TestResolveImports(t *testing.T) { // Check error assert.NoError(t, err) assert.Equal(t, "/tmp/", resolved.Imports["abs/"]) - assert.Equal(t, cwd+"/common", resolved.Imports["root"]) - assert.Equal(t, cwd+"/supabase/tests", resolved.Imports["parent"]) - assert.Equal(t, cwd+"/supabase/functions/child/", resolved.Imports["child"]) + assert.Equal(t, filepath.ToSlash(cwd+"/common"), filepath.ToSlash(resolved.Imports["root"])) + assert.Equal(t, filepath.ToSlash(cwd+"/supabase/tests"), filepath.ToSlash(resolved.Imports["parent"])) + assert.Equal(t, filepath.ToSlash(cwd+"/supabase/functions/child/"), filepath.ToSlash(resolved.Imports["child"])) assert.Equal(t, "../missing", resolved.Imports["missing"]) }) diff --git a/pkg/config/auth_test.go b/pkg/config/auth_test.go index df53ba80b..2a80f35e7 100644 --- a/pkg/config/auth_test.go +++ b/pkg/config/auth_test.go @@ -3,6 +3,7 @@ package config import ( "os" "path/filepath" + "strings" "testing" "time" @@ -31,7 +32,18 @@ func assertSnapshotEqual(t *testing.T, actual []byte) { assert.NoError(t, os.MkdirAll(filepath.Dir(snapshot), 0755)) assert.NoError(t, os.WriteFile(snapshot, actual, 0600)) } - assert.Equal(t, string(expected), string(actual)) + // Normalize line endings in both expected and actual + expectedStr := normalizeLineEndings(string(expected)) + actualStr := normalizeLineEndings(string(actual)) + assert.Equal(t, expectedStr, actualStr) +} + +func normalizeLineEndings(s string) string { + // First normalize to Unix-style line endings + s = strings.ReplaceAll(s, "\r\n", "\n") + // Then normalize any remaining Windows-style line endings + s = strings.ReplaceAll(s, "\r", "\n") + return s } func TestAuthDiff(t *testing.T) { diff --git a/pkg/config/testdata/detects_differences.snapshot b/pkg/config/testdata/detects_differences.snapshot new file mode 100644 index 000000000..5d0e9603e --- /dev/null +++ b/pkg/config/testdata/detects_differences.snapshot @@ -0,0 +1,14 @@ +diff remote[api] local[api] +--- remote[api] ++++ local[api] +@@ -1,7 +1,7 @@ + enabled = true +-schemas = ["public"] +-extra_search_path = ["public"] +-max_rows = 500 ++schemas = ["public", "private"] ++extra_search_path = ["extensions", "public"] ++max_rows = 1000 + port = 0 + external_url = "" + diff --git a/pkg/config/testdata/enable_sign_up_without_provider.snapshot b/pkg/config/testdata/enable_sign_up_without_provider.snapshot new file mode 100644 index 000000000..a7c312c91 --- /dev/null +++ b/pkg/config/testdata/enable_sign_up_without_provider.snapshot @@ -0,0 +1,12 @@ +diff remote[auth] local[auth] +--- remote[auth] ++++ local[auth] +@@ -40,7 +40,7 @@ + otp_expiry = 0 + + [sms] +-enable_signup = false ++enable_signup = true + enable_confirmations = false + template = "" + max_frequency = "0s" diff --git a/pkg/config/testdata/handles_api_disabled_on_local_side.snapshot b/pkg/config/testdata/handles_api_disabled_on_local_side.snapshot new file mode 100644 index 000000000..67a5ccd5c --- /dev/null +++ b/pkg/config/testdata/handles_api_disabled_on_local_side.snapshot @@ -0,0 +1,9 @@ +diff remote[api] local[api] +--- remote[api] ++++ local[api] +@@ -1,4 +1,4 @@ +-enabled = true ++enabled = false + schemas = ["public"] + extra_search_path = ["public"] + max_rows = 500 diff --git a/pkg/config/testdata/handles_api_disabled_on_remote_side.snapshot b/pkg/config/testdata/handles_api_disabled_on_remote_side.snapshot new file mode 100644 index 000000000..200d36c40 --- /dev/null +++ b/pkg/config/testdata/handles_api_disabled_on_remote_side.snapshot @@ -0,0 +1,9 @@ +diff remote[api] local[api] +--- remote[api] ++++ local[api] +@@ -1,4 +1,4 @@ +-enabled = false ++enabled = true + schemas = ["public", "private"] + extra_search_path = ["extensions", "public"] + max_rows = 500 diff --git a/pkg/config/testdata/local_disabled_remote_enabled.snapshot b/pkg/config/testdata/local_disabled_remote_enabled.snapshot new file mode 100644 index 000000000..84085ccd4 --- /dev/null +++ b/pkg/config/testdata/local_disabled_remote_enabled.snapshot @@ -0,0 +1,12 @@ +diff remote[auth] local[auth] +--- remote[auth] ++++ local[auth] +@@ -10,7 +10,7 @@ + password_requirements = "" + + [captcha] +-enabled = true ++enabled = false + provider = "turnstile" + secret = "hash:ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e" + diff --git a/pkg/config/testdata/local_enabled_and_disabled.snapshot b/pkg/config/testdata/local_enabled_and_disabled.snapshot new file mode 100644 index 000000000..b4022569c --- /dev/null +++ b/pkg/config/testdata/local_enabled_and_disabled.snapshot @@ -0,0 +1,28 @@ +diff remote[auth] local[auth] +--- remote[auth] ++++ local[auth] +@@ -1,14 +1,14 @@ + enabled = false +-site_url = "" +-additional_redirect_urls = ["https://127.0.0.1:3000", "https://ref.supabase.co"] +-jwt_expiry = 0 +-enable_refresh_token_rotation = true +-refresh_token_reuse_interval = 0 +-enable_manual_linking = true +-enable_signup = true +-enable_anonymous_sign_ins = true +-minimum_password_length = 8 +-password_requirements = "letters_digits" ++site_url = "http://127.0.0.1:3000" ++additional_redirect_urls = ["https://127.0.0.1:3000"] ++jwt_expiry = 3600 ++enable_refresh_token_rotation = false ++refresh_token_reuse_interval = 10 ++enable_manual_linking = false ++enable_signup = false ++enable_anonymous_sign_ins = false ++minimum_password_length = 6 ++password_requirements = "lower_upper_letters_digits_symbols" + + [hook] + diff --git a/pkg/config/testdata/local_enabled_remote_disabled.snapshot b/pkg/config/testdata/local_enabled_remote_disabled.snapshot new file mode 100644 index 000000000..43bb8802b --- /dev/null +++ b/pkg/config/testdata/local_enabled_remote_disabled.snapshot @@ -0,0 +1,16 @@ +diff remote[auth] local[auth] +--- remote[auth] ++++ local[auth] +@@ -10,9 +10,9 @@ + password_requirements = "" + + [captcha] +-enabled = false +-provider = "hcaptcha" +-secret = "hash:ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252" ++enabled = true ++provider = "turnstile" ++secret = "hash:ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e" + + [hook] + diff --git a/pkg/parser/token_test.go b/pkg/parser/token_test.go index 566b11867..ab1dcaf48 100644 --- a/pkg/parser/token_test.go +++ b/pkg/parser/token_test.go @@ -13,6 +13,10 @@ import ( "github.com/stretchr/testify/require" ) +// normalizeLineEndings replaces all \r\n with \n in a string +func normalizeLineEndings(s string) string { + return strings.ReplaceAll(s, "\r\n", "\n") +} func TestSplit(t *testing.T) { const testdata = "testdata" @@ -39,6 +43,16 @@ func TestSplit(t *testing.T) { stats, err := Split(sql) require.NoError(t, err) + // Add single newline to match expected output + fixture = append(fixture, "\n") + + // Before each comparison: + for i := range fixture { + fixture[i] = normalizeLineEndings(fixture[i]) + } + for i := range stats { + stats[i] = normalizeLineEndings(stats[i]) + } assert.ElementsMatch(t, fixture, stats) }