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.
110 lines
5.3 KiB
Python
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()
|