feat: funciones Go — core (cron, join_by_key, validate_struct), datascience (pivot, diff_entities), infra (http, cache, cron_ticker)
Nuevas funciones Go con tests en tres dominios: - core: parse_cron_expr, next_cron_time, join_by_key, validate_struct_fields + tipo CronSchedule - datascience: pivot (tabla dinámica), diff_entities (comparación de entidades) - infra: http_get_json, http_post_json, http_download_file, cache_to_sqlite, cron_ticker Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package datascience
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDiffEntities(t *testing.T) {
|
||||
t.Run("entity añadida", func(t *testing.T) {
|
||||
before := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
{"id": "2", "name": "Bob"},
|
||||
}
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
added := result["added"].([]map[string]any)
|
||||
if len(added) != 1 {
|
||||
t.Errorf("expected 1 added, got %d", len(added))
|
||||
}
|
||||
if added[0]["id"] != "2" {
|
||||
t.Errorf("expected added id=2, got %v", added[0]["id"])
|
||||
}
|
||||
if result["unchanged"].(int) != 1 {
|
||||
t.Errorf("expected 1 unchanged, got %v", result["unchanged"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("entity eliminada", func(t *testing.T) {
|
||||
before := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
{"id": "2", "name": "Bob"},
|
||||
}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
}
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
removed := result["removed"].([]map[string]any)
|
||||
if len(removed) != 1 {
|
||||
t.Errorf("expected 1 removed, got %d", len(removed))
|
||||
}
|
||||
if removed[0]["id"] != "2" {
|
||||
t.Errorf("expected removed id=2, got %v", removed[0]["id"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("entity modificada con detalle de campos", func(t *testing.T) {
|
||||
before := []map[string]any{
|
||||
{"id": "1", "name": "Alice", "status": "active"},
|
||||
}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice", "status": "inactive"},
|
||||
}
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
modified := result["modified"].([]map[string]any)
|
||||
if len(modified) != 1 {
|
||||
t.Errorf("expected 1 modified, got %d", len(modified))
|
||||
}
|
||||
changes := modified[0]["changes"].(map[string]any)
|
||||
statusChange, ok := changes["status"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected status change, got %v", changes)
|
||||
}
|
||||
if statusChange["old"] != "active" {
|
||||
t.Errorf("expected old=active, got %v", statusChange["old"])
|
||||
}
|
||||
if statusChange["new"] != "inactive" {
|
||||
t.Errorf("expected new=inactive, got %v", statusChange["new"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("entities identicas → unchanged", func(t *testing.T) {
|
||||
entities := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
{"id": "2", "name": "Bob"},
|
||||
}
|
||||
result := DiffEntities(entities, entities, "id", nil)
|
||||
if result["unchanged"].(int) != 2 {
|
||||
t.Errorf("expected 2 unchanged, got %v", result["unchanged"])
|
||||
}
|
||||
if len(result["added"].([]map[string]any)) != 0 {
|
||||
t.Errorf("expected 0 added")
|
||||
}
|
||||
if len(result["modified"].([]map[string]any)) != 0 {
|
||||
t.Errorf("expected 0 modified")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ignore_fields funciona", func(t *testing.T) {
|
||||
before := []map[string]any{
|
||||
{"id": "1", "name": "Alice", "updated_at": "2024-01-01"},
|
||||
}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice", "updated_at": "2024-06-01"},
|
||||
}
|
||||
// Default ignores updated_at
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
if result["unchanged"].(int) != 1 {
|
||||
t.Errorf("expected 1 unchanged (updated_at ignored), got %v", result["unchanged"])
|
||||
}
|
||||
modified := result["modified"].([]map[string]any)
|
||||
if len(modified) != 0 {
|
||||
t.Errorf("expected 0 modified when updated_at is ignored, got %d", len(modified))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("lista vacia vs lista con datos", func(t *testing.T) {
|
||||
before := []map[string]any{}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
}
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
added := result["added"].([]map[string]any)
|
||||
if len(added) != 1 {
|
||||
t.Errorf("expected 1 added, got %d", len(added))
|
||||
}
|
||||
if result["unchanged"].(int) != 0 {
|
||||
t.Errorf("expected 0 unchanged")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("summary format correcto", func(t *testing.T) {
|
||||
before := []map[string]any{
|
||||
{"id": "1", "name": "Alice"},
|
||||
{"id": "3", "name": "Carol"},
|
||||
}
|
||||
after := []map[string]any{
|
||||
{"id": "1", "name": "Alice Changed"},
|
||||
{"id": "2", "name": "Bob"},
|
||||
}
|
||||
result := DiffEntities(before, after, "id", nil)
|
||||
summary := result["summary"].(string)
|
||||
expected := "1 added, 1 removed, 1 modified, 0 unchanged"
|
||||
if summary != expected {
|
||||
t.Errorf("expected summary %q, got %q", expected, summary)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user