caudal/programa/pruebas/test_ejemplo.py
esetheyers 7e18576f86 Caudal 0.2.0
Taxes for the whole of Spain (common territory, Navarre, Álava, Bizkaia and Gipuzkoa); flats, garages and land valued on their own; Treasury bills, bonds and deposits priced on BME; broker accounts; a guided start; a page per investment with its chart and the tax of selling today; net worth at the top; undo when deleting; Woodpecker CI for the tests and the Linux build.
2026-10-15 16:49:15 -05:00

110 lines
5.3 KiB
Python

"""
Pruebas de la cartera de ejemplo: quien abre la aplicación por primera vez
puede curiosear con datos inventados sin que su cartera se toque ni se mezcle.
python3 -m unittest discover -s pruebas -v
"""
from __future__ import annotations
import datetime as dt
import sys
import tempfile
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from cartera import servidor # noqa: E402
from cartera.operaciones import Cartera, ErrorOperacion # noqa: E402
class TestEjemplo(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.carpeta = Path(self.tmp.name) / "datos"
self.real = Cartera(self.carpeta)
self.addCleanup(self.real.cerrar)
self.real.guardar_activo({"nombre": "Mi fondo", "tipo": "Fondo"})
self.app = servidor.App(self.real)
self.addCleanup(lambda: self.app.ejemplo(False))
def nombres(self):
return [a["nombre"] for a in self.app.estado()["activos"]]
def test_una_cartera_vacia_ofrece_el_ejemplo(self):
e = self.app.estado()
self.assertEqual((e["ejemplo"], e["hay_ejemplo"]), (False, True))
def test_entrar_ensena_la_de_mentira_y_salir_devuelve_la_tuya_intacta(self):
antes = sorted(f.name for f in self.carpeta.iterdir())
self.assertEqual(self.app.ejemplo(True), {"ejemplo": True})
e = self.app.estado()
self.assertTrue(e["ejemplo"])
self.assertNotIn("Mi fondo", self.nombres())
self.assertGreater(e["resumen"]["global"]["valor"], 0)
temporal = self.app.cartera.carpeta
self.assertNotEqual(temporal, self.carpeta)
self.assertEqual(self.app.ejemplo(False), {"ejemplo": False})
self.assertEqual(self.nombres(), ["Mi fondo"])
self.assertIs(self.app.cartera, self.real)
self.assertFalse(temporal.exists()) # lo del ejemplo se tira
self.assertEqual(sorted(f.name for f in self.carpeta.iterdir()), antes)
def test_lo_que_se_hace_en_el_ejemplo_no_llega_a_la_cartera_de_verdad(self):
self.app.ejemplo(True)
self.app.cartera.guardar_activo({"nombre": "Prueba dentro del ejemplo", "tipo": "Accion"})
self.assertIn("Prueba dentro del ejemplo", self.nombres())
self.app.ejemplo(False)
self.assertEqual(self.nombres(), ["Mi fondo"])
self.assertNotIn("Prueba dentro del ejemplo", (self.carpeta / "activos.jsonl").read_text(encoding="utf-8"))
def test_los_precios_del_ejemplo_estan_al_dia_y_no_se_descargan(self):
self.app.ejemplo(True)
hoy = dt.date.today().isoformat()
# Los de mercado, de hoy; los que Caudal estima (inmuebles, la Letra) llevan su propia fecha
precios = sorted(self.app.cartera.datos.vivos("precios"), key=lambda p: p["fecha"])
fechas = {p["activo"]: p["fecha"] for p in precios if p.get("fuente") == "ejemplo"}
self.assertEqual(set(fechas.values()), {hoy})
self.assertEqual({p["fuente"] for p in precios} - {"ejemplo"}, {"IPV", "MAPA", "devengo", "compra"})
self.assertFalse([a for a in self.app.estado()["resumen"]["avisos"] if a["tipo"] == "precio"])
with self.assertRaises(ErrorOperacion):
self.app.actualizar_precios()
def test_el_ejemplo_solo_tiene_inversiones_corrientes_y_parece_al_dia(self):
self.app.ejemplo(True)
e = self.app.estado()
hoy = dt.date.today()
self.assertEqual(sorted({a["tipo"] for a in e["activos"]}),
["Accion", "Cripto", "Cuenta", "Deuda", "ETF", "Fondo", "Inmueble", "RentaFija"])
# Lo que se estima solo sale ya calculado, con las fechas desplazadas
filas = {f["nombre"]: f for f in e["resumen"]["abiertos"]}
self.assertEqual((filas["Piso alquilado"]["fuente_precio"], filas["Finca de cereal"]["fuente_precio"],
filas["Letra del Tesoro a 12 meses"]["fuente_precio"]), ("IPV", "MAPA", "devengo"))
self.assertGreater(e["resumen"]["global"]["deuda"], 0)
letra = next(a for a in e["activos"] if a["tipo"] == "RentaFija")
self.assertGreater(letra["renta_fija"]["vencimiento"], hoy.isoformat())
self.assertEqual(e["activos"][0]["nombre"], "Bitcoin")
hoy = dt.date.today()
ultima = max(dt.date.fromisoformat(m["fecha"]) for m in e["movimientos"])
self.assertLess((hoy - ultima).days, 45) # la última operación es de hace poco, se abra cuando se abra
self.assertFalse(any(dt.date.fromisoformat(m["fecha"]) > hoy for m in e["movimientos"]))
self.assertGreater(e["resumen"]["global"]["valor"], 10000)
self.assertGreater(e["resumen"]["global"]["liquidez"], 0)
self.assertGreater(len(e["resumen"]["evolucion"]), 6)
fiscal = self.app.fiscal(str(hoy.year - 1))
self.assertTrue(fiscal["ejercicios"])
def test_entrar_dos_veces_o_salir_sin_haber_entrado_no_rompe_nada(self):
self.assertEqual(self.app.ejemplo(False), {"ejemplo": False})
self.app.ejemplo(True)
primera = self.app.cartera
self.app.ejemplo(True)
self.assertIs(self.app.cartera, primera)
self.app.ejemplo(False)
self.assertIs(self.app.cartera, self.real)
if __name__ == "__main__":
unittest.main()