Pipeline completo de publicação no LinkedIn: evaluator → redator → editor → art → director → publisher - Seed com 37 posts em _sugestoes.md - Sorteio de formato com N=3 bloqueados (format-history) - Reciclagem mensal de posts com rotação de formato - Revisão via Telegram com chat livre (Gemini 2.5 Flash) - Publicação via LinkedIn API (OAuth2) - Makefile com targets para Windows/Linux/ARM64 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
2.4 KiB
Go
85 lines
2.4 KiB
Go
package formats_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"ldpost/shared/formats"
|
|
)
|
|
|
|
func TestSortearFormato_NeverReturnsBlocked(t *testing.T) {
|
|
blocked := []string{"como", "erro", "porque"}
|
|
allowed := map[string]bool{"checklist": true, "comparacao": true, "bastidor": true}
|
|
|
|
for i := 0; i < 100; i++ {
|
|
got := formats.SortearFormato(blocked)
|
|
if !allowed[got] {
|
|
t.Errorf("iteração %d: retornou formato bloqueado %q", i, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSortearFormato_AllBlocked_Fallback(t *testing.T) {
|
|
// All 6 blocked → should still return something valid
|
|
allFormatos := []string{"como", "erro", "porque", "checklist", "comparacao", "bastidor"}
|
|
got := formats.SortearFormato(allFormatos)
|
|
if err := formats.ValidarFormato(got); err != nil {
|
|
t.Errorf("fallback retornou formato inválido %q: %v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestSortearFormato_WeightDistribution(t *testing.T) {
|
|
// Run 2000 samples with no blocked formats.
|
|
// "como" has weight 5 out of total 12 ≈ 41.7%
|
|
// Expected range after 2000 trials: ~35-50%
|
|
counts := make(map[string]int)
|
|
const n = 2000
|
|
for i := 0; i < n; i++ {
|
|
f := formats.SortearFormato(nil)
|
|
counts[f]++
|
|
}
|
|
|
|
comoRatio := float64(counts["como"]) / float64(n)
|
|
if comoRatio < 0.35 || comoRatio > 0.55 {
|
|
t.Errorf("\"como\" apareceu %.1f%% das vezes (esperado 35-55%%)", comoRatio*100)
|
|
}
|
|
|
|
// Verify all formats appear at least once
|
|
for _, f := range []string{"como", "erro", "porque", "checklist", "comparacao", "bastidor"} {
|
|
if counts[f] == 0 {
|
|
t.Errorf("formato %q nunca foi sorteado em %d iterações", f, n)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidarFormato(t *testing.T) {
|
|
valid := []string{"como", "erro", "porque", "checklist", "comparacao", "bastidor"}
|
|
for _, f := range valid {
|
|
if err := formats.ValidarFormato(f); err != nil {
|
|
t.Errorf("ValidarFormato(%q) retornou erro inesperado: %v", f, err)
|
|
}
|
|
}
|
|
|
|
invalid := []string{"", "tutorial", "video", "COMO", "Como"}
|
|
for _, f := range invalid {
|
|
if err := formats.ValidarFormato(f); err == nil {
|
|
t.Errorf("ValidarFormato(%q) deveria retornar erro", f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFormatLabel(t *testing.T) {
|
|
cases := map[string]string{
|
|
"como": "Como fazer",
|
|
"erro": "Erro clássico",
|
|
"porque": "Por que",
|
|
"checklist": "Checklist",
|
|
"comparacao": "Comparação",
|
|
"bastidor": "Bastidor",
|
|
}
|
|
for input, want := range cases {
|
|
if got := formats.FormatLabel(input); got != want {
|
|
t.Errorf("FormatLabel(%q) = %q, want %q", input, got, want)
|
|
}
|
|
}
|
|
}
|