package postimport import ( "os" "path/filepath" "strings" "testing" ) func TestNormalizeLegacyTime(t *testing.T) { got, err := normalizeLegacyTime("2026-01-13 01:25:27.486491+00") if err != nil { t.Fatal(err) } if got != "2026-01-13T01:25:27Z" { t.Fatalf("normalized time = %q", got) } } func TestArticleToPostFallbackSlugAndBody(t *testing.T) { root := t.TempDir() postsDir := filepath.Join(root, defaultPostsDir) if err := os.MkdirAll(postsDir, 0o755); err != nil { t.Fatal(err) } post, skipped, err := articleToPost(root, postsDir, csvArticle{ Title: "Hello World", BodyMD: "\nBody\n", Status: "published", CreatedAt: "2026-01-13 01:25:27.486491+00", UpdatedAt: "2026-01-13 01:25:27.486491+00", PublishedAt: "2026-01-13 01:25:27.486491+00", Type: "post", }, false) if err != nil { t.Fatal(err) } if skipped { t.Fatal("expected importable post") } if post.Frontmatter.Slug != "hello-world" { t.Fatalf("slug = %q", post.Frontmatter.Slug) } if post.Body != "Body\n" { t.Fatalf("body = %q", post.Body) } if post.Frontmatter.PublishedAt == nil || *post.Frontmatter.PublishedAt != "2026-01-13T01:25:27Z" { t.Fatalf("published_at = %#v", post.Frontmatter.PublishedAt) } } func TestArticleToPostSkipsExistingWithoutOverwrite(t *testing.T) { root := t.TempDir() postsDir := filepath.Join(root, defaultPostsDir) if err := os.MkdirAll(postsDir, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(postsDir, "smoking.md"), []byte("existing"), 0o644); err != nil { t.Fatal(err) } _, skipped, err := articleToPost(root, postsDir, csvArticle{ Slug: "smoking", Title: "抽烟", BodyMD: "Body", Status: "published", CreatedAt: "2026-01-13 01:25:27.486491+00", UpdatedAt: "2026-01-13 01:25:27.486491+00", Type: "post", }, false) if err != nil { t.Fatal(err) } if !skipped { t.Fatal("expected existing file to be skipped") } } func TestImportWritesMarkdown(t *testing.T) { root := t.TempDir() if err := os.MkdirAll(filepath.Join(root, "backend", "cmd", "osaetctl"), 0o755); err != nil { t.Fatal(err) } if err := os.MkdirAll(filepath.Join(root, "frontend", "site"), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "frontend", "site", "package.json"), []byte("{}"), 0o644); err != nil { t.Fatal(err) } csvPath := filepath.Join(root, "articles.csv") csvContent := strings.Join([]string{ "id,slug,title,body_md,body_html,status,archive_id,author_id,published_at,created_at,updated_at,type", "post-1,test-post,Test Post,\"Line 1\n\nLine 2\",,published,,,2026-01-13 01:25:27.486491+00,2026-01-13 01:25:27.486491+00,2026-01-13 01:25:27.486491+00,post", }, "\n") if err := os.WriteFile(csvPath, []byte(csvContent), 0o644); err != nil { t.Fatal(err) } result, err := Import(Options{CSVPath: csvPath, PostsDir: defaultPostsDir, WorkingDir: root}) if err != nil { t.Fatal(err) } if result.Imported != 1 || result.SkippedExisting != 0 || result.SkippedNonPost != 0 { t.Fatalf("result = %#v", result) } data, err := os.ReadFile(filepath.Join(root, defaultPostsDir, "test-post.md")) if err != nil { t.Fatal(err) } content := string(data) for _, want := range []string{ "slug: test-post", "title: Test Post", "status: published", "published_at: \"2026-01-13T01:25:27Z\"", "Line 1", "Line 2", } { if !strings.Contains(content, want) { t.Fatalf("expected output to contain %q\n%s", want, content) } } }