You've already forked lazarus-ccr
fpspreadsheet: Add test case for switched decimal and thousand separators in csv file. Fix bugs related to that.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3674 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -561,7 +561,7 @@ begin
|
|||||||
if CSVParams.NumberFormat <> '' then
|
if CSVParams.NumberFormat <> '' then
|
||||||
s := Format(CSVParams.NumberFormat, [AValue], CSVParams.FormatSettings)
|
s := Format(CSVParams.NumberFormat, [AValue], CSVParams.FormatSettings)
|
||||||
else
|
else
|
||||||
s := FWorksheet.ReadAsUTF8Text(ACell);
|
s := FWorksheet.ReadAsUTF8Text(ACell, CSVParams.FormatSettings);
|
||||||
AppendToStream(AStream, s);
|
AppendToStream(AStream, s);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -523,6 +523,7 @@ type
|
|||||||
{ Reading of values }
|
{ Reading of values }
|
||||||
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring; overload;
|
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring; overload;
|
||||||
function ReadAsUTF8Text(ACell: PCell): ansistring; overload;
|
function ReadAsUTF8Text(ACell: PCell): ansistring; overload;
|
||||||
|
function ReadAsUTF8Text(ACell: PCell; AFormatSettings: TFormatSettings): ansistring; overload;
|
||||||
function ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
|
function ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
|
||||||
function ReadAsNumber(ACell: PCell): Double; overload;
|
function ReadAsNumber(ACell: PCell): Double; overload;
|
||||||
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
|
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
|
||||||
@ -2384,23 +2385,26 @@ end;
|
|||||||
@return The text representation of the cell
|
@return The text representation of the cell
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
|
function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
|
||||||
|
begin
|
||||||
|
Result := ReadAsUTF8Text(ACell, FWorkbook.FormatSettings);
|
||||||
|
end;
|
||||||
|
|
||||||
function FloatToStrNoNaN(const Value: Double;
|
function TsWorksheet.ReadAsUTF8Text(ACell: PCell;
|
||||||
|
AFormatSettings: TFormatSettings): ansistring;
|
||||||
|
|
||||||
|
function FloatToStrNoNaN(const AValue: Double;
|
||||||
ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
|
ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
|
||||||
var
|
|
||||||
fs: TFormatSettings;
|
|
||||||
begin
|
begin
|
||||||
fs := FWorkbook.FormatSettings;
|
if IsNan(AValue) then
|
||||||
if IsNan(Value) then
|
|
||||||
Result := ''
|
Result := ''
|
||||||
else
|
else
|
||||||
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
|
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
|
||||||
Result := FloatToStr(Value, fs)
|
Result := FloatToStr(AValue, AFormatSettings)
|
||||||
else
|
else
|
||||||
if (ANumberFormat = nfPercentage) then
|
if (ANumberFormat = nfPercentage) then
|
||||||
Result := FormatFloat(ANumberFormatStr, Value*100, fs)
|
Result := FormatFloat(ANumberFormatStr, AValue*100, AFormatSettings)
|
||||||
else
|
else
|
||||||
Result := FormatFloat(ANumberFormatStr, Value, fs)
|
Result := FormatFloat(ANumberFormatStr, AValue, AFormatSettings)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function DateTimeToStrNoNaN(const Value: Double;
|
function DateTimeToStrNoNaN(const Value: Double;
|
||||||
@ -2414,15 +2418,15 @@ function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
|
|||||||
if (ANumberFormat = nfGeneral) then
|
if (ANumberFormat = nfGeneral) then
|
||||||
begin
|
begin
|
||||||
if frac(Value) = 0 then // date only
|
if frac(Value) = 0 then // date only
|
||||||
ANumberFormatStr := Workbook.FormatSettings.ShortDateFormat
|
ANumberFormatStr := AFormatSettings.ShortDateFormat
|
||||||
else if trunc(Value) = 0 then // time only
|
else if trunc(Value) = 0 then // time only
|
||||||
ANumberFormatStr := Workbook.FormatSettings.LongTimeFormat
|
ANumberFormatStr := AFormatSettings.LongTimeFormat
|
||||||
else
|
else
|
||||||
ANumberFormatStr := 'cc'
|
ANumberFormatStr := 'cc'
|
||||||
end else
|
end else
|
||||||
if ANumberFormatStr = '' then
|
if ANumberFormatStr = '' then
|
||||||
ANumberFormatStr := BuildDateTimeFormatString(ANumberFormat,
|
ANumberFormatStr := BuildDateTimeFormatString(ANumberFormat,
|
||||||
Workbook.FormatSettings, ANumberFormatStr);
|
AFormatSettings, ANumberFormatStr);
|
||||||
|
|
||||||
// Saw strange cases in ods where date/time formats contained pos/neg/zero parts.
|
// Saw strange cases in ods where date/time formats contained pos/neg/zero parts.
|
||||||
// Split to be on the safe side.
|
// Split to be on the safe side.
|
||||||
|
@ -119,8 +119,6 @@ function SpecialDateTimeFormat(ACode: String;
|
|||||||
procedure SplitFormatString(const AFormatString: String; out APositivePart,
|
procedure SplitFormatString(const AFormatString: String; out APositivePart,
|
||||||
ANegativePart, AZeroPart: String);
|
ANegativePart, AZeroPart: String);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
|
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
|
||||||
|
|
||||||
// These two functions are copies of fpc trunk until they are available in stable fpc.
|
// These two functions are copies of fpc trunk until they are available in stable fpc.
|
||||||
@ -1558,10 +1556,11 @@ begin
|
|||||||
dec(i);
|
dec(i);
|
||||||
while i >= 1 do
|
while i >= 1 do
|
||||||
begin
|
begin
|
||||||
if not (AText[i] in ['0'..'9', '+', '-']) then
|
if not (AText[i] in ['0'..'9', '+', '-', '.', ',']) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// If we find the testSep character again it must be a thousand separator.
|
// If we find the testSep character again it must be a thousand separator,
|
||||||
|
// and there are no decimals.
|
||||||
if (AText[i] = testSep) then
|
if (AText[i] = testSep) then
|
||||||
begin
|
begin
|
||||||
// ... but only if there are 3 numerical digits in between
|
// ... but only if there are 3 numerical digits in between
|
||||||
@ -1573,8 +1572,8 @@ begin
|
|||||||
fs.DecimalSeparator := ','
|
fs.DecimalSeparator := ','
|
||||||
else
|
else
|
||||||
fs.DecimalSeparator := '.';
|
fs.DecimalSeparator := '.';
|
||||||
ADecimalSeparator := fs.DecimalSeparator;
|
|
||||||
AThousandSeparator := fs.ThousandSeparator;
|
AThousandSeparator := fs.ThousandSeparator;
|
||||||
|
ADecimalSeparator := #0; // this indicates that there are no decimals
|
||||||
done := true;
|
done := true;
|
||||||
i := 0;
|
i := 0;
|
||||||
end else
|
end else
|
||||||
|
@ -65,7 +65,8 @@ type
|
|||||||
// Test word wrapping
|
// Test word wrapping
|
||||||
procedure TestWriteRead_WordWrap(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteRead_WordWrap(AFormat: TsSpreadsheetFormat);
|
||||||
// Test number formats
|
// Test number formats
|
||||||
procedure TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat;
|
||||||
|
AVariant: Integer = 0);
|
||||||
// Repeat with date/times
|
// Repeat with date/times
|
||||||
procedure TestWriteRead_DateTimeFormats(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteRead_DateTimeFormats(AFormat: TsSpreadsheetFormat);
|
||||||
// Test merged cells
|
// Test merged cells
|
||||||
@ -137,13 +138,14 @@ type
|
|||||||
procedure TestWriteRead_OOXML_WordWrap;
|
procedure TestWriteRead_OOXML_WordWrap;
|
||||||
|
|
||||||
{ CSV Tests }
|
{ CSV Tests }
|
||||||
procedure TestWriteRead_CSV_NumberFormats;
|
procedure TestWriteRead_CSV_NumberFormats_0;
|
||||||
|
procedure TestWriteRead_CSV_NumberFormats_1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
TypInfo, fpsutils;
|
TypInfo, fpsutils, fpscsv;
|
||||||
|
|
||||||
const
|
const
|
||||||
FmtNumbersSheet = 'NumbersFormat'; //let's distinguish it from the regular numbers sheet
|
FmtNumbersSheet = 'NumbersFormat'; //let's distinguish it from the regular numbers sheet
|
||||||
@ -165,14 +167,18 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
fs: TFormatSettings;
|
fs: TFormatSettings;
|
||||||
myworkbook: TsWorkbook;
|
myworkbook: TsWorkbook;
|
||||||
|
ch: Char;
|
||||||
begin
|
begin
|
||||||
// Set up norm - MUST match spreadsheet cells exactly
|
// Set up norm - MUST match spreadsheet cells exactly
|
||||||
|
|
||||||
// The workbook uses a slightly modified copy of the DefaultFormatSettings
|
// The workbook uses a slightly modified copy of the DefaultFormatSettings
|
||||||
// We create a copy here in order to better define the predicted strings.
|
// We create a copy here in order to better define the predicted strings.
|
||||||
myWorkbook := TsWorkbook.Create;
|
myWorkbook := TsWorkbook.Create;
|
||||||
fs := MyWorkbook.FormatSettings;
|
try
|
||||||
myWorkbook.Free;
|
fs := MyWorkbook.FormatSettings;
|
||||||
|
finally
|
||||||
|
myWorkbook.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
// Numbers
|
// Numbers
|
||||||
SollNumbers[0] := 0.0;
|
SollNumbers[0] := 0.0;
|
||||||
@ -299,21 +305,33 @@ end;
|
|||||||
|
|
||||||
{ --- Number format tests --- }
|
{ --- Number format tests --- }
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat);
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat;
|
||||||
|
AVariant: Integer = 0);
|
||||||
var
|
var
|
||||||
MyWorksheet: TsWorksheet;
|
MyWorksheet: TsWorksheet;
|
||||||
MyWorkbook: TsWorkbook;
|
MyWorkbook: TsWorkbook;
|
||||||
ActualString: String;
|
ActualString: String;
|
||||||
|
ExpectedString: String;
|
||||||
Row, Col: Integer;
|
Row, Col: Integer;
|
||||||
TempFile: string; //write xls/xml to this file and read back from it
|
TempFile: string; //write xls/xml to this file and read back from it
|
||||||
begin
|
begin
|
||||||
{// Not needed: use workbook.writetofile with overwrite=true
|
|
||||||
if fileexists(TempFile) then
|
|
||||||
DeleteFile(TempFile);
|
|
||||||
}
|
|
||||||
// Write out all test values
|
// Write out all test values
|
||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
|
if (AFormat = sfCSV) then
|
||||||
|
begin
|
||||||
|
case AVariant of
|
||||||
|
0: begin
|
||||||
|
CSVParams.FormatSettings.DecimalSeparator := MyWorkbook.FormatSettings.DecimalSeparator;
|
||||||
|
CSVParams.FormatSettings.ThousandSeparator := MyWorkbook.FormatSettings.ThousandSeparator;
|
||||||
|
end;
|
||||||
|
1: begin // interchanged decimal and thousand separators
|
||||||
|
CSVParams.FormatSettings.ThousandSeparator := MyWorkbook.FormatSettings.DecimalSeparator;
|
||||||
|
CSVParams.FormatSettings.DecimalSeparator := MyWorkbook.FormatSettings.ThousandSeparator;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet);
|
MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet);
|
||||||
for Row := Low(SollNumbers) to High(SollNumbers) do
|
for Row := Low(SollNumbers) to High(SollNumbers) do
|
||||||
for Col := ord(Low(SollNumberFormats)) to ord(High(SollNumberFormats)) do
|
for Col := ord(Low(SollNumberFormats)) to ord(High(SollNumberFormats)) do
|
||||||
@ -343,17 +361,18 @@ begin
|
|||||||
for Col := Low(SollNumberFormats) to High(SollNumberFormats) do
|
for Col := Low(SollNumberFormats) to High(SollNumberFormats) do
|
||||||
begin
|
begin
|
||||||
ActualString := MyWorkSheet.ReadAsUTF8Text(Row,Col);
|
ActualString := MyWorkSheet.ReadAsUTF8Text(Row,Col);
|
||||||
if (SollNumberStrings[Row,Col] <> ActualString) then
|
ExpectedString := SollNumberStrings[Row, Col];
|
||||||
|
if (ExpectedString <> ActualString) then
|
||||||
begin
|
begin
|
||||||
if (AFormat = sfCSV) and (Row=5) and (Col=0) then
|
if (AFormat = sfCSV) and (Row=5) and (Col=0) then
|
||||||
// CSV has an insignificant difference of tiny numbers in
|
// CSV has an insignificant difference of tiny numbers in
|
||||||
// general format
|
// general format
|
||||||
ignore('Ignoring insignificant saved string mismatch, cell ' +
|
ignore('Ignoring insignificant saved string mismatch, cell ' +
|
||||||
CellNotation(MyWorksheet,Row,Col) +
|
CellNotation(MyWorksheet,Row,Col) +
|
||||||
', expected: <' + SollNumberStrings[Row,Col] +
|
', expected: <' + ExpectedString +
|
||||||
'> but was: <' + ActualString + '>')
|
'> but was: <' + ActualString + '>')
|
||||||
else
|
else
|
||||||
CheckEquals(SollNumberStrings[Row,Col], ActualString,
|
CheckEquals(ExpectedString, ActualString,
|
||||||
'Test saved string mismatch, cell '+CellNotation(MyWorkSheet,Row,Col));
|
'Test saved string mismatch, cell '+CellNotation(MyWorkSheet,Row,Col));
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -388,9 +407,14 @@ begin
|
|||||||
TestWriteRead_NumberFormats(sfOOXML);
|
TestWriteRead_NumberFormats(sfOOXML);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats;
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats_0;
|
||||||
begin
|
begin
|
||||||
TestWriteRead_NumberFormats(sfCSV);
|
TestWriteRead_NumberFormats(sfCSV, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats_1;
|
||||||
|
begin
|
||||||
|
TestWriteRead_NumberFormats(sfCSV, 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user