depanare_testare_vfp.md 226->118 linii, testare-ui-vfp.md 133->90. - regula SAFETY/dialog modal si -A -T erau enuntate de 3 ori -> o data - cele 3 capcane "proces agatat" -> un singur algoritm de diagnostic in 3 pasi - studiul de caz CNRCRT si detaliile ROAGEST (jtva_coloane2, achizitie_import) reduse la regula generala + pointer catre scriptul de test - reguli_lucru pct.4 ramane doar pointer, fara detaliile duplicate de mediu - sters docs/bash.exe.stackdump (fisier de gunoi, negitat) Masuratorile si datele concrete pastrate integral. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RqJ7D5ftMbChDyz5mpVkCd
127 lines
8.5 KiB
Markdown
127 lines
8.5 KiB
Markdown
# Depanare si testare VFP fara IDE (headless)
|
|
|
|
Metoda de depanare a bug-urilor runtime VFP, valabila pentru toate proiectele ROA.
|
|
Complementara cu `flux-editare-vfp-text.md` (editare .vcx/.scx pe text), `cautare_vcx_vct.md`
|
|
(cautare in binare) si `testare-ui-vfp.md` (teste cu formular vizibil + screenshots).
|
|
Reguli de livrare: `reguli_lucru.md`.
|
|
|
|
## 1. Fisiere de mediu si exemple
|
|
|
|
- `COMUN\utile\Teste\test_init_env_auto.prg` - initializare completa de mediu FARA
|
|
interactiune (parametri: host, schema, parola; implicit CENTRAL / MARIUSM_AUTO, parola
|
|
schemei `ROMFASTSOFT`; user aplicatie "MARIUS M" / "123"). Seteaza PATH/CLASSLIB/PROCEDURE
|
|
ca programul principal si instantiaza goConn/goExecutor/goApp/goLog/goFirma/goCalendar +
|
|
pachetele de sesiune Oracle. Dupa apel poti face `CREATEOBJECT('frm_xxx')` si apela metodele
|
|
punctual. Varianta interactiva (INPUTBOX + meniu): `COMUN\programe\test_init_env.prg`.
|
|
- `COMUN\utile\Teste\test_repro_cnrcrt_footer.prg` - harness model: init mediu -> replicare
|
|
flux -> instantiere forma reala -> executie pas cu pas cu logare -> verdict OK/BUG.
|
|
- `COMUN\utile\Teste\test_repro_import_nota.prg` - harness fara Oracle (cursori + goExecutor
|
|
dummy) cu parametru care incarca o copie de clasa din scratchpad, pentru bisectie A/B.
|
|
|
|
## 2. Rulare headless
|
|
|
|
`vfp9.exe -c<config.fpw> -A -T "<script.prg>" <param>`, lansat din PowerShell cu timeout:
|
|
```
|
|
$p = Start-Process 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' -ArgumentList '-A','-T','"D:\...\script.prg" PARAM' -PassThru
|
|
$p.WaitForExit(120000); if (!$p.HasExited) { $p.Kill() }
|
|
```
|
|
- `-A` ignora config.fpw implicit, `-T` sare peste splash; **ambele obligatorii** - fara `-T`
|
|
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare).
|
|
Un `-c<cale>` explicit (lipit de flag) e preluat chiar si impreuna cu `-A`.
|
|
- **SAFETY**: sub `-A` porneste ON, deci primul `STRTOFILE` peste un log existent (sau
|
|
`COMPILE` peste un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul
|
|
pare agatat. Pune `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF` +
|
|
`RESOURCE=OFF` intr-un config.fpw propriu pasat cu `-c`. Verificare: logheaza
|
|
`SET("SAFETY")`/`SET("RESOURCE")` la start.
|
|
- In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola);
|
|
`ON ERROR DO <handler> WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si
|
|
continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final.
|
|
- `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata +
|
|
linia `PROCEDURE`.
|
|
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi
|
|
daca ai editat scriptul intre rulari.
|
|
- Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau
|
|
seteaza `WindowType = 0`.
|
|
|
|
## 3. Citirea log-ului aplicatiei (log.txt din radacina proiectului)
|
|
|
|
`ErrorHandler` scrie `nErrror`, `cMethod`, `line` (0 daca exe-ul e fara debug info) si stack-ul.
|
|
Semantica ON ERROR, esentiala la interpretare:
|
|
- Dupa RETURN din handler executia CONTINUA de la linia urmatoare => o singura cauza produce
|
|
CASCADE de erori. Tipar clasic: eroare pe `WITH <expr>` => liniile `.prop=` dau 1940
|
|
"Expression is not valid outside of WITH/ENDWITH", `ENDWITH` da 1939. **Prima eroare din
|
|
secventa e cea reala**, restul e zgomot.
|
|
- Erorile din TRY/CATCH nu ajung in log. Un CATCH gol poate ascunde ani un defect latent care
|
|
"explodeaza" cand codul din jur se repara.
|
|
- Liniile "ON..." din stack sunt dispatch-uri (ON ERROR / READ EVENTS), nu metode reale.
|
|
|
|
## 4. Verificare de sintaxa prin compilare headless (dupa orice editare de `.prg`)
|
|
|
|
Cel mai ieftin test dupa o modificare: `COMPILE` headless, fara aplicatie si fara Oracle.
|
|
- Compileaza o COPIE a fisierului in scratchpad, nu sursa din working copy (`COMPILE` scrie
|
|
`.fxp` langa `.prg`, care ar aparea ca modificare in SVN). VFP nu rezolva simboluri externe
|
|
la compilare, deci copia izolata e suficienta pentru sintaxa.
|
|
- Sterge `.err`-ul vechi INAINTE de `COMPILE`; verdictul = existenta lui `<nume>.err` dupa
|
|
(exista => logheaza continutul; nu exista => compilare curata).
|
|
- Nu inlocuieste testul functional: prinde sintaxa, nu apeluri catre metode inexistente.
|
|
|
|
## 5. Bisectia versiunilor de clase (regresii)
|
|
|
|
Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
|
|
1. `git show <rev>:clase\fisier.vcx > temp\fisier.vcx` (+ `.vct`); pentru diff lizibil,
|
|
`vcx2txt.ps1 -Source temp\fisier.vcx -CacheRoot temp\txt`.
|
|
2. In harness incarca DOAR copia (`SET CLASSLIB TO temp\fisier.vcx`), **nu ADDITIVE peste cea
|
|
reala** - rezolvarea intre doua classlib-uri cu aceeasi clasa nu e garantata => fals negativ.
|
|
3. Fara git, din backup-urile de runda: copiaza `*.vc2.pre_rundaN.bak` intr-un temp si
|
|
regenereaza binarul cu `FoxBin2Prg.EXE "<temp>\fisier.vc2" "" "" "" 1 0 1` (pune
|
|
`..\include\foxpro.h` langa, altfel `.ERR`).
|
|
4. Bisectie in interiorul unei runde: neutralizeaza valori IN LOC (ControlSource -> camp
|
|
simplu, sterge linii de proprietate) - NU sterge obiecte/coloane din `ADD OBJECT` (strica
|
|
structura: "Cannot add this object to a Grid").
|
|
5. Cand diferenta apare dupa un fix "inofensiv" in COMUN, cauza poate fi un defect latent
|
|
activat de fix (cod care nu rulase niciodata incepe sa ruleze), nu diff-ul in sine.
|
|
|
|
## 6. Capcane VFP (de verificat la bug-uri asemanatoare)
|
|
|
|
- **`SELECT ... INTO CURSOR` NU mosteneste indecsii sursei.** Orice `Seek(...,'cursor','tag')`
|
|
pe copie crapa; recreeaza indexul dupa copiere. Acelasi lucru pentru cursorii creati intr-un
|
|
test: trebuie sa aiba EXACT indecsii pe care ii creeaza fluxul real inainte de instantiere,
|
|
altfel ordinea/logica difera si testul da rezultat fals.
|
|
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca un
|
|
ControlSource crapa la re-evaluare in timp ce coloanele sunt atinse programatic (ex. font per
|
|
coloana la Init). Simptome in aval: `attachtogrid` copiaza 0 coloane, apoi `calctotal` da
|
|
"Property <cColWithLabel> is not found". Similar, un cursor legat la grid recreat de Init
|
|
lasa grid-ul fara coloane (eroare 1925).
|
|
- **ControlSource-uri cu campuri inexistente sunt tolerate la afisare**, dar orice expresie
|
|
care ARUNCA eroare la evaluare (Seek pe tag lipsa, functie nedefinita) declanseaza cazul
|
|
de mai sus. Repro/regresie: `utile\Teste\test_repro_cnrcrt_footer.prg`.
|
|
- **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`** Fara el: eroare 9
|
|
"Data type mismatch" la `CREATEOBJECT`-ul formei (faza de constructie, raportata la linia
|
|
apelanta, Details gol).
|
|
- **Erorile de instantiere sunt raportate la linia `CREATEOBJECT`, nu la `.Init`**: daca
|
|
`Procedure` = scriptul apelant, eroarea vine din evaluarea definitiei clasei (`ADD OBJECT ...
|
|
WITH RowSource`, ControlSource-expresie), pentru ca bind-ul controalelor native se rezolva la
|
|
CONSTRUCTIE, inainte de `Init`.
|
|
- **Literal string > 255 caractere = eroare de COMPILARE, nu de runtime** (masurat 24.07.2026:
|
|
255 trece, 256 pica). Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de
|
|
metoda, `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul
|
|
programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la
|
|
ea. De aceea SQL-ul lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau
|
|
concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
|
|
|
|
## 7. Capcane la SCRIEREA scriptului de test
|
|
|
|
- **`DEFINE CLASS ... ENDDEFINE` nu poate sta la mijlocul programului principal.** Toate liniile
|
|
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul
|
|
ruleaza doar pana acolo si se opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe
|
|
pare agatat la nesfarsit. Pune orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
|
|
- **Dummy-uri cu metode**: `CREATEOBJECT('Custom')` + `AddProperty()` adauga doar PROPRIETATI.
|
|
Daca clasa testata apeleaza `goExecutor.oExecute(...)`, dummy-ul trebuie sa fie
|
|
`DEFINE CLASS dummyexecutor AS Custom` cu `PROCEDURE oExecute` reala.
|
|
- **Diagnostic "script agatat"**, in ordine: (1) exista `<script>.ERR` langa `.prg`? => s-a
|
|
oprit la compilare; (2) CPU-ul procesului ~0 dupa cateva secunde (`Get-Process | select CPU`)
|
|
=> asteapta un dialog modal, nu proceseaza; confirma enumerand ferestrele procesului cu
|
|
`EnumWindows`/`GetWindowText`/`GetWindowThreadProcessId` (`Add-Type`, user32) filtrat pe PID -
|
|
daca vezi doar fereastra principala + "Command", nu e dialog, cauta alta cauza (tipic `-T`
|
|
lipsa). Confirma mereu cauza inainte de a schimba scriptul.
|