diff --git a/SerialPort.pas b/SerialPort.pas index 3279251..7368415 100644 --- a/SerialPort.pas +++ b/SerialPort.pas @@ -424,14 +424,20 @@ begin end; function SerValid(Handle: TSerialHandle): Boolean; +// ★Ноль значит РАЗНОЕ на разных системах, и одной проверкой тут не обойтись. begin - // ★Ноль — ЗАКОННЫЙ дескриптор на Unix: если стандартный ввод закрыт (демон, - // запуск из службы), fpOpen отдаст именно 0, и объявлять такой порт ошибкой - // нельзя — он не только не заработает, но и не закроется, потому что - // SerClose тоже смотрит сюда. Признак неудачи ровно один и на всех - // платформах: SER_INVALID_HANDLE. Ноль, который RTL под Windows отдаёт при - // отказе, переводится в него внутри SerOpen. +{$IFDEF WINDOWS} + // Ядро Windows нулевой хендл не выдаёт никогда: ноль здесь — либо отказ RTL + // (SerOpen переводит его в SER_INVALID_HANDLE), либо просто неинициализированное + // поле. Отвергаем, чтобы контракт был верен и для значения, пришедшего извне. + Result := (Handle <> SER_INVALID_HANDLE) and (Handle <> 0); +{$ELSE} + // А на Unix ноль ЗАКОНЕН: при закрытом стандартном вводе (демон, запуск из + // службы) fpOpen отдаст именно его. Объявить такой порт ошибкой значит не + // только потерять рабочий порт, но и не закрыть дескриптор — SerClose + // смотрит сюда же. Признак неудачи один: SER_INVALID_HANDLE. Result := Handle <> SER_INVALID_HANDLE; +{$ENDIF} end; function SerDefaultPortName(Index: Integer): string; diff --git a/test/platform/run.sh b/test/platform/run.sh index fdde5ed..e34d79e 100755 --- a/test/platform/run.sh +++ b/test/platform/run.sh @@ -62,6 +62,22 @@ sim_build() { # $1 = win|mac sim_build win sim_build mac +# ── Прогон WINDOWS-ветки, а не только её компиляция ────────────────────────── +# ★Заглушка модуля Serial — чистый Паскаль, поэтому ветку можно не только +# собрать, но и ЗАПУСТИТЬ: проверяются перевод нулевого хендла RTL в +# SER_INVALID_HANDLE, ответ SerValid (под Windows ноль негоден — в отличие от +# Unix) и правило имени COM10+. +cp win_probe/winprobe.pas "$WORK/win/" +COUNT=$((COUNT + 1)) +if ( cd "$WORK/win" && fpc -B -Mobjfpc -dHEADLESS -dSIMWIN -Fu. -FU. \ + -o./winprobe winprobe.pas >"$WORK/win/probe.log" 2>&1 && ./winprobe ); then + echo " ok SerialPort.pas: ветка win ведёт себя как надо (прогон на заглушке)" +else + echo " FAIL SerialPort.pas: прогон windows-ветки провалился" + cat "$WORK/win/probe.log" + FAILED=$((FAILED + 1)) +fi + echo echo "Итого: $COUNT проверок, провалено $FAILED" [ "$FAILED" -eq 0 ] diff --git a/test/platform/win_probe/winprobe.pas b/test/platform/win_probe/winprobe.pas new file mode 100644 index 0000000..64ca3a2 --- /dev/null +++ b/test/platform/win_probe/winprobe.pas @@ -0,0 +1,56 @@ +program winprobe; + +{ + Прогон WINDOWS-ветки SerialPort.pas на Linux. + + ★Компиляции мало. Соседняя проверка (-Cn) ловит синтаксис и разрешение имён, + но не поведение, а под Windows у обёртки своя логика: перевод нулевого хендла + RTL в SER_INVALID_HANDLE и свой ответ SerValid (ядро Windows нулевой хендл не + выдаёт никогда, значит ноль там негоден — в отличие от Unix, где это законный + дескриптор при закрытом стандартном вводе). Всё это чистая логика поверх + заглушки модуля Serial, поэтому её можно и нужно прогнать здесь. +} + +{$MODE Delphi} + +uses + SysUtils, SerialPort; + +var + Passed, Failed: Integer; + +procedure Check(const Name: string; Cond: Boolean; const Extra: string = ''); +begin + if Cond then + begin + Inc(Passed); + WriteLn(' ok ', Name); + end + else + begin + Inc(Failed); + if Extra <> '' then WriteLn(' FAIL ', Name, ' ', Extra) + else WriteLn(' FAIL ', Name); + end; +end; + +begin + Passed := 0; + Failed := 0; + WriteLn(' -- прогон WINDOWS-ветки SerialPort на заглушке'); + + // Заглушка Serial.SerOpen всегда отдаёт ноль — то есть «не открылось» по + // соглашению RTL под Windows. Обёртка обязана перевести это в свой признак. + Check('★отказ RTL (ноль) переводится в SER_INVALID_HANDLE', + SerOpen('COM1') = SER_INVALID_HANDLE, IntToStr(SerOpen('COM1'))); + Check('★нулевой хендл под Windows негоден', not SerValid(0)); + Check('SER_INVALID_HANDLE негоден', not SerValid(SER_INVALID_HANDLE)); + Check('обычный хендл годен', SerValid(5)); + + Check('COM1 остаётся коротким', SerWinDeviceName('COM1') = 'COM1'); + Check('COM10 получает префикс', SerWinDeviceName('COM10') = '\\.\COM10'); + + WriteLn(Format(' -- ветка windows: %d проверок, провалено %d', + [Passed + Failed, Failed])); + if Failed > 0 then Halt(1); +end. diff --git a/test/serial/README.md b/test/serial/README.md index b4ac347..c124c31 100644 --- a/test/serial/README.md +++ b/test/serial/README.md @@ -47,5 +47,7 @@ test/serial/run.sh псевдотерминале не работает. Это остаётся на живой порт с железкой — там же проверяется и телеграфный ключ на `CWKeyer`. -Компиляцию платформенных ветвей (Windows, macOS) проверяет соседний стенд -`test/platform`. +Платформенные ветви (Windows, macOS) проверяет соседний стенд `test/platform`: +компиляцию обеих, а windows-ветку ещё и прогоном на заглушке модуля `Serial` — +перевод нулевого хендла RTL в `SER_INVALID_HANDLE`, ответ `SerValid` (там ноль +негоден, в отличие от Unix) и правило имени `COM10+`.