1c4a4b9259
Cinco funciones nuevas para soportar DuckDB como fuente de verdad del project osint:
Grupo duckdb (escritura, complementan a duckdb_query_readonly):
- duckdb_execute_py_infra (impure): ejecuta INSERT/UPDATE/DELETE/DDL en read-write, commit, {status,rowcount}. 6 tests.
- duckdb_upsert_py_infra (impure): UPSERT ON CONFLICT actualizando solo update_cols → ownership selectivo (un re-upsert no pisa columnas excluidas). 7 tests.
Grupo dav (libretas de contactos + vCard multi-valor):
- dav_make_addressbook_py_infra (impure): crea una libreta CardDAV nueva via extended MKCOL (RFC 5689). Idempotente. 12 tests.
- dav_list_addressbooks_py_infra (impure): lista las libretas del contacts-home (PROPFIND Depth:1). 7 tests.
- build_vcard_py_core (pure): serializa un contacto a vCard 3.0 multi-valor (N TEL/EMAIL/ADR + X-OSINT-*). 5 tests.
Paginas de capacidad duckdb.md y dav.md actualizadas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
"""Tests para dav_make_addressbook.
|
|
|
|
La funcion publica es impura (hace HTTP), asi que no se prueba contra un servidor
|
|
real. Se ejercitan los helpers puros extraidos a nivel de modulo: la
|
|
sanitizacion del slug, la construccion de la URL de la coleccion y la generacion
|
|
del cuerpo XML del MKCOL extendido (resourcetype addressbook + displayname +
|
|
descripcion escapados). Sin red.
|
|
"""
|
|
|
|
from infra.dav_make_addressbook import (
|
|
_build_mkcol_xml,
|
|
_join_url,
|
|
_sanitize_slug,
|
|
)
|
|
|
|
|
|
def test_sanitize_slug_minusculas():
|
|
assert _sanitize_slug("Trabajo") == "trabajo"
|
|
|
|
|
|
def test_sanitize_slug_espacios_a_guion():
|
|
assert _sanitize_slug("agenda de trabajo") == "agenda-de-trabajo"
|
|
|
|
|
|
def test_sanitize_slug_elimina_caracteres_raros():
|
|
assert _sanitize_slug("Casa/Ocio!! 2026") == "casaocio-2026"
|
|
|
|
|
|
def test_sanitize_slug_colapsa_guiones_y_recorta():
|
|
assert _sanitize_slug(" --Foo Bar-- ") == "foo-bar"
|
|
|
|
|
|
def test_sanitize_slug_vacio():
|
|
assert _sanitize_slug(" !!! ") == ""
|
|
|
|
|
|
def test_join_url_compone_la_coleccion():
|
|
url = _join_url(
|
|
"https://dav-x.organic-machine.com",
|
|
"/enmanuel/contacts/",
|
|
"trabajo",
|
|
)
|
|
assert url == "https://dav-x.organic-machine.com/enmanuel/contacts/trabajo/"
|
|
|
|
|
|
def test_mkcol_xml_es_mkcol_extendido():
|
|
xml = _build_mkcol_xml("Trabajo")
|
|
assert "<D:mkcol" in xml
|
|
assert 'xmlns:C="urn:ietf:params:xml:ns:carddav"' in xml
|
|
|
|
|
|
def test_mkcol_xml_declara_resourcetype_addressbook():
|
|
xml = _build_mkcol_xml("Trabajo")
|
|
assert "<D:resourcetype><D:collection/><C:addressbook/></D:resourcetype>" in xml
|
|
|
|
|
|
def test_mkcol_xml_incluye_displayname():
|
|
xml = _build_mkcol_xml("Trabajo")
|
|
assert "<D:displayname>Trabajo</D:displayname>" in xml
|
|
|
|
|
|
def test_mkcol_xml_escapa_displayname():
|
|
xml = _build_mkcol_xml("Casa & <Ocio>")
|
|
assert "Casa & <Ocio>" in xml
|
|
assert "<Ocio>" not in xml
|
|
|
|
|
|
def test_mkcol_xml_incluye_y_escapa_descripcion():
|
|
xml = _build_mkcol_xml("Trabajo", description="A & B <c>")
|
|
assert (
|
|
"<C:addressbook-description>A & B <c></C:addressbook-description>"
|
|
in xml
|
|
)
|
|
|
|
|
|
def test_mkcol_xml_omite_descripcion_vacia():
|
|
xml = _build_mkcol_xml("Trabajo")
|
|
assert "addressbook-description" not in xml
|