"""Teste pentru app.web.integrare_examples — modul PUR, fara I/O. Ordinea: RED (fara implementare) -> GREEN (dupa implementare). """ import json import pytest from app.models import PrezentareIn from app.web.integrare_examples import exemple BASE_URL = "https://autopass.example.com" ACCOUNT_ID = 7 RESULT = exemple(BASE_URL, ACCOUNT_ID) LIMBAJE_OBLIGATORII = ["curl", "python", "php", "csharp", "node", "vfp_msxml", "vfp_winhttp"] # --------------------------------------------------------------------------- # Structura de baza # --------------------------------------------------------------------------- def test_toate_limbajele_prezente(): """Toate limbajele obligatorii trebuie sa fie chei in dictionar.""" for limbaj in LIMBAJE_OBLIGATORII: assert limbaj in RESULT, f"lipseste limbajul: {limbaj}" def test_ambele_canale_per_limbaj(): """Fiecare limbaj are atat 'prezentari' cat si 'import'.""" for limbaj in LIMBAJE_OBLIGATORII: assert "prezentari" in RESULT[limbaj], f"{limbaj} lipseste canalul 'prezentari'" assert "import" in RESULT[limbaj], f"{limbaj} lipseste canalul 'import'" assert isinstance(RESULT[limbaj]["prezentari"], str), f"{limbaj}.prezentari nu e string" assert isinstance(RESULT[limbaj]["import"], str), f"{limbaj}.import nu e string" # --------------------------------------------------------------------------- # curl — prezentari # --------------------------------------------------------------------------- def test_snippet_curl_prezentari_contine_endpoint_si_header(): """Snippetul curl prezentari contine URL-ul corect si header-ul X-API-Key.""" snippet = RESULT["curl"]["prezentari"] assert f"{BASE_URL}/v1/prezentari" in snippet, "lipseste endpoint-ul /v1/prezentari" assert "X-API-Key" in snippet, "lipseste header-ul X-API-Key" assert "rfak_..." in snippet, "placeholder-ul cheii trebuie sa fie rfak_..." # --------------------------------------------------------------------------- # python — import (multipart) # --------------------------------------------------------------------------- def test_snippet_python_import_upload_multipart(): """Snippetul python import foloseste multipart (files=) pe /v1/import.""" snippet = RESULT["python"]["import"] assert f"{BASE_URL}/v1/import" in snippet, "lipseste endpoint-ul /v1/import" assert "files=" in snippet or 'files =' in snippet, "lipseste multipart files=" assert "rfak_..." in snippet, "placeholder-ul cheii trebuie sa fie rfak_..." # --------------------------------------------------------------------------- # VFP — doua dialecte distincte # --------------------------------------------------------------------------- def test_vfp_msxml_si_winhttp_distincte(): """vfp_msxml foloseste MSXML2.ServerXMLHTTP.6.0; vfp_winhttp foloseste WinHttp.WinHttpRequest.5.1.""" msxml_snippet = RESULT["vfp_msxml"]["prezentari"] winhttp_snippet = RESULT["vfp_winhttp"]["prezentari"] assert "MSXML2.ServerXMLHTTP.6.0" in msxml_snippet, ( "vfp_msxml trebuie sa foloseasca MSXML2.ServerXMLHTTP.6.0" ) assert "WinHttp.WinHttpRequest.5.1" in winhttp_snippet, ( "vfp_winhttp trebuie sa foloseasca WinHttp.WinHttpRequest.5.1" ) # Distincte — nu acelasi obiect COM in ambele assert "MSXML2.ServerXMLHTTP.6.0" not in winhttp_snippet, ( "vfp_winhttp nu trebuie sa contina MSXML2 (dialect gresit)" ) assert "WinHttp.WinHttpRequest.5.1" not in msxml_snippet, ( "vfp_msxml nu trebuie sa contina WinHttp (dialect gresit)" ) # --------------------------------------------------------------------------- # Drift-test schema — campuri obligatorii din model # --------------------------------------------------------------------------- def test_payload_acopera_campurile_obligatorii_din_model(): """Snippetul curl prezentari contine toate campurile obligatorii din PrezentareIn. Deriva lista din model_fields pentru a fi rezistenta la schimbari de schema. Campurile cu default (odometru_initial, obs, b64_image, sistem_reparat) nu sunt obligatorii si nu trebuie sa cauzeze drift fals. """ obligatorii = { camp for camp, field in PrezentareIn.model_fields.items() if field.is_required() } # Obligatorii asteptate conform spec: vin, nr_inmatriculare, data_prestatie, # odometru_final, prestatii snippet = RESULT["curl"]["prezentari"] for camp in obligatorii: assert camp in snippet, f"camp obligatoriu absent din snippet: {camp}" # Credentiale RAR (email + password) assert "email" in snippet, "camp 'email' absent din snippet (RarCredentials)" assert "password" in snippet, "camp 'password' absent din snippet (RarCredentials)" def test_prestatii_in_snippet_are_cod(): """Snippetul prezentari contine cod_prestatie sau cod_op_service in payload.""" for limbaj in LIMBAJE_OBLIGATORII: snippet = RESULT[limbaj]["prezentari"] are_cod = "cod_prestatie" in snippet or "cod_op_service" in snippet assert are_cod, f"{limbaj}.prezentari lipseste cod_prestatie / cod_op_service" # --------------------------------------------------------------------------- # Placeholder cheie # --------------------------------------------------------------------------- def test_placeholder_cheie_nu_e_valoare_reala(): """Toate snippet-urile cu autentificare contin literal 'rfak_', nu o cheie reala.""" for limbaj in LIMBAJE_OBLIGATORII: for canal in ["prezentari", "import"]: snippet = RESULT[limbaj][canal] assert "rfak_" in snippet, ( f"{limbaj}.{canal} lipseste placeholder-ul rfak_ (cheie API)" ) # --------------------------------------------------------------------------- # FIX-1 — C# si VFP: JSON compact (fara newline in string literal) # --------------------------------------------------------------------------- def test_csharp_payload_pe_o_singura_linie(): """Snippetul C# prezentari: JSON-ul din var json = "..." e pe o singura linie. Un JSON multi-linie intr-un string literal C# NU compileaza. Verificam ca helper-ul compact produce un JSON fara newline si ca acel JSON compact apare in snippetul C#. """ from app.web.integrare_examples import _payload_json_compact, _snippet_csharp_prezentari compact = _payload_json_compact(ACCOUNT_ID) assert "\n" not in compact, ( "_payload_json_compact produce newline — nu e compact" ) snippet = _snippet_csharp_prezentari(BASE_URL, ACCOUNT_ID) # JSON-ul compact (cu ghilimele escape-uite) trebuie sa fie substring in snippet escaped = compact.replace('"', '\\"') assert escaped in snippet, ( "JSON-ul compact (escaped) nu apare in snippetul C#; " "probabil _snippet_csharp_prezentari inca foloseste _payload_json_str" ) # Verificare directa: linia var json = "..." nu contine newline in interiorul ei # In C# linia se termina cu "; (ghilimea de inchidere + punct-virgula) for line in snippet.splitlines(): if 'var json = "' in line: stripped = line.rstrip() # Linia trebuie sa se inchida pe acelasi rand (cu "; sau ") assert stripped.endswith('";') or stripped.endswith('"'), ( f"Linia 'var json = \"...' nu se termina pe acelasi rand: {line!r}" ) break else: assert False, "Linia 'var json = \"...' nu a fost gasita in snippetul C#" def test_vfp_payload_pe_o_singura_linie(): """Snippetul VFP prezentari (ambele dialecte): cPayload = "..." e pe o linie. Un string literal VFP multi-linie NU e valid. Verificam ambele dialecte: vfp_msxml si vfp_winhttp. """ from app.web.integrare_examples import _payload_json_compact compact = _payload_json_compact(ACCOUNT_ID) # In VFP ghilimele se dubleaza compact_vfp = compact.replace('"', '""') for dialect in ("vfp_msxml", "vfp_winhttp"): snippet = RESULT[dialect]["prezentari"] # Payload-ul VFP (cu doubling) trebuie sa fie substring in snippet assert compact_vfp in snippet, ( f"{dialect}: JSON-ul compact (cu \"\" doubling) nu apare in snippet; " "probabil inca se foloseste _payload_json_str cu indent" ) # Linia cPayload = "..." nu trebuie sa contina newline in interiorul valorii for line in snippet.splitlines(): if 'cPayload = "' in line: assert line.rstrip().endswith('"'), ( f"{dialect}: linia 'cPayload = \"...' nu se termina pe acelasi rand: {line!r}" ) break else: assert False, f"{dialect}: linia 'cPayload = \"...' nu a fost gasita in snippet" # --------------------------------------------------------------------------- # FIX-2 — Node import: FormData/Blob globale, fara import din node:buffer # --------------------------------------------------------------------------- def test_node_import_nu_foloseste_node_buffer(): """Snippetul Node import nu importa din 'node:buffer' si foloseste FormData globala. 'node:buffer' nu exporta FormData — `new FormData()` ar arunca TypeError. In Node 18+ FormData si Blob sunt globale. """ snippet = RESULT["node"]["import"] assert "node:buffer" not in snippet, ( "Snippetul Node import contine 'node:buffer' — invalid, FormData nu e acolo" ) assert "new FormData()" in snippet, ( "Snippetul Node import nu contine 'new FormData()' — FormData trebuie folosita global" )