fix(stdlib): TStringList.Text/LoadFromFile preserve verbatim lines
SplitIntoList — the sole backend for TStringList.SetText and LoadFromFile — trimmed leading and trailing spaces from each split segment. That is correct for CSV-style splitting but wrong for line-splitting: a TStringList must store each line verbatim, including indentation. Removed the trimming so each segment is added as Copy(S, Start, Len) untouched. SplitIntoList has exactly one caller (SetText), so no trimming-dependent code is affected. This also fixes a latent test-infrastructure bug: the threaded test runner parses each subprocess suite's stdout via TStringList.Text and identifies failure-detail lines by their two-space indentation. With indentation stripped, those lines never matched, AddFailure was never called, and the merged result reported zero failures — so the plain summary printed OK even when [Threaded] suites failed. With lines preserved, the summary now correctly reports failures. Regression test: TestRun_TextSet_PreservesLeadingWhitespace asserts on raw stdout so the spaces inside [] are checked without round-tripping through Text. Self-hosting fixpoint verified clean.
This commit is contained in:
parent
99b7761bf4
commit
576f60d807
|
|
@ -39,6 +39,7 @@ type
|
|||
procedure TestRun_TextGet;
|
||||
procedure TestRun_TextGet_ManyLines;
|
||||
procedure TestRun_TextSet;
|
||||
procedure TestRun_TextSet_PreservesLeadingWhitespace;
|
||||
procedure TestRun_GrowBeyondInitialCapacity;
|
||||
procedure TestRun_Sorted_Add_OrderedOutput;
|
||||
procedure TestRun_Sorted_Find;
|
||||
|
|
@ -278,6 +279,31 @@ const
|
|||
end.
|
||||
''';
|
||||
|
||||
{ Text/LoadFromFile must preserve each line verbatim, including leading and
|
||||
trailing whitespace — standard TStringList semantics. Regression for the
|
||||
SplitIntoList trimming bug that silently dropped indentation (which in turn
|
||||
masked failures in the threaded test-runner's subprocess output parser).
|
||||
The program prints each line wrapped in [] so the harness can see the
|
||||
surrounding spaces without itself round-tripping through Text. }
|
||||
SrcTextSetPreservesWhitespace =
|
||||
'''
|
||||
program P;
|
||||
uses Classes;
|
||||
var L: TStringList; I: Integer;
|
||||
begin
|
||||
L := TStringList.Create;
|
||||
L.Text := 'a' + #10 + ' indented' + #10 + 'trailing ';
|
||||
WriteLn(L.Count);
|
||||
I := 0;
|
||||
while I < L.Count do
|
||||
begin
|
||||
WriteLn('[' + L.Get(I) + ']');
|
||||
I := I + 1
|
||||
end;
|
||||
L.Free
|
||||
end.
|
||||
''';
|
||||
|
||||
SrcGrow =
|
||||
'''
|
||||
program P;
|
||||
|
|
@ -694,6 +720,22 @@ begin
|
|||
end
|
||||
end;
|
||||
|
||||
procedure TE2ETStringListTests.TestRun_TextSet_PreservesLeadingWhitespace;
|
||||
var
|
||||
Output: string;
|
||||
RCode: Integer;
|
||||
begin
|
||||
if not ToolchainAvailable then begin Fail('<toolchain-missing>'); Exit end;
|
||||
AssertTrue('compile+run',
|
||||
CompileAndRunWithRTL(SrcTextSetPreservesWhitespace, Output, RCode));
|
||||
AssertEquals('exit 0', 0, RCode);
|
||||
{ Assert on the raw stdout so the leading/trailing spaces inside [] are
|
||||
checked directly, without round-tripping through Text. }
|
||||
AssertEquals('verbatim lines preserved',
|
||||
'3' + #10 + '[a]' + #10 + '[ indented]' + #10 + '[trailing ]' + #10,
|
||||
Output);
|
||||
end;
|
||||
|
||||
procedure TE2ETStringListTests.TestRun_GrowBeyondInitialCapacity;
|
||||
var
|
||||
Output: string;
|
||||
|
|
|
|||
|
|
@ -273,9 +273,12 @@ procedure SplitIntoList(const S: string; ASep: Integer; AList: TStringList);
|
|||
var
|
||||
I: Integer;
|
||||
Start: Integer;
|
||||
SLo: Integer;
|
||||
SHi: Integer;
|
||||
begin
|
||||
{ Line-splitter for TStringList.Text / LoadFromFile. Each segment between
|
||||
separators is added verbatim — leading and trailing whitespace is part of
|
||||
the line and must be preserved (standard TStringList semantics). Trimming
|
||||
here previously stripped indentation, which silently corrupted any
|
||||
whitespace-significant text round-tripped through Text. }
|
||||
AList.Clear;
|
||||
Start := 0;
|
||||
I := 0;
|
||||
|
|
@ -283,24 +286,13 @@ begin
|
|||
begin
|
||||
if OrdAt(S, I) = ASep then
|
||||
begin
|
||||
{ Trim surrounding spaces }
|
||||
SLo := Start;
|
||||
SHi := I - 1;
|
||||
while (SLo <= SHi) and (OrdAt(S, SLo) = 32) do SLo := SLo + 1;
|
||||
while (SHi >= SLo) and (OrdAt(S, SHi) = 32) do SHi := SHi - 1;
|
||||
AList.Add(Copy(S, SLo, SHi - SLo + 1));
|
||||
AList.Add(Copy(S, Start, I - Start));
|
||||
Start := I + 1;
|
||||
end;
|
||||
I := I + 1;
|
||||
end;
|
||||
if Start < Length(S) then
|
||||
begin
|
||||
SLo := Start;
|
||||
SHi := Length(S) - 1;
|
||||
while (SLo <= SHi) and (OrdAt(S, SLo) = 32) do SLo := SLo + 1;
|
||||
while (SHi >= SLo) and (OrdAt(S, SHi) = 32) do SHi := SHi - 1;
|
||||
AList.Add(Copy(S, SLo, SHi - SLo + 1));
|
||||
end;
|
||||
AList.Add(Copy(S, Start, Length(S) - Start));
|
||||
end;
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue