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:
wp_xxyyzz
2014-10-20 23:17:07 +00:00
parent e8351807cc
commit 8891b0a90b
4 changed files with 59 additions and 32 deletions

View File

@ -561,7 +561,7 @@ begin
if CSVParams.NumberFormat <> '' then
s := Format(CSVParams.NumberFormat, [AValue], CSVParams.FormatSettings)
else
s := FWorksheet.ReadAsUTF8Text(ACell);
s := FWorksheet.ReadAsUTF8Text(ACell, CSVParams.FormatSettings);
AppendToStream(AStream, s);
end;

View File

@ -523,6 +523,7 @@ type
{ Reading of values }
function ReadAsUTF8Text(ARow, ACol: Cardinal): 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(ACell: PCell): Double; overload;
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
@ -2384,23 +2385,26 @@ end;
@return The text representation of the cell
-------------------------------------------------------------------------------}
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;
var
fs: TFormatSettings;
begin
fs := FWorkbook.FormatSettings;
if IsNan(Value) then
if IsNan(AValue) then
Result := ''
else
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
Result := FloatToStr(Value, fs)
Result := FloatToStr(AValue, AFormatSettings)
else
if (ANumberFormat = nfPercentage) then
Result := FormatFloat(ANumberFormatStr, Value*100, fs)
Result := FormatFloat(ANumberFormatStr, AValue*100, AFormatSettings)
else
Result := FormatFloat(ANumberFormatStr, Value, fs)
Result := FormatFloat(ANumberFormatStr, AValue, AFormatSettings)
end;
function DateTimeToStrNoNaN(const Value: Double;
@ -2414,15 +2418,15 @@ function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
if (ANumberFormat = nfGeneral) then
begin
if frac(Value) = 0 then // date only
ANumberFormatStr := Workbook.FormatSettings.ShortDateFormat
ANumberFormatStr := AFormatSettings.ShortDateFormat
else if trunc(Value) = 0 then // time only
ANumberFormatStr := Workbook.FormatSettings.LongTimeFormat
ANumberFormatStr := AFormatSettings.LongTimeFormat
else
ANumberFormatStr := 'cc'
end else
if ANumberFormatStr = '' then
ANumberFormatStr := BuildDateTimeFormatString(ANumberFormat,
Workbook.FormatSettings, ANumberFormatStr);
AFormatSettings, ANumberFormatStr);
// Saw strange cases in ods where date/time formats contained pos/neg/zero parts.
// Split to be on the safe side.

View File

@ -119,8 +119,6 @@ function SpecialDateTimeFormat(ACode: String;
procedure SplitFormatString(const AFormatString: String; out APositivePart,
ANegativePart, AZeroPart: String);
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
// These two functions are copies of fpc trunk until they are available in stable fpc.
@ -1558,10 +1556,11 @@ begin
dec(i);
while i >= 1 do
begin
if not (AText[i] in ['0'..'9', '+', '-']) then
if not (AText[i] in ['0'..'9', '+', '-', '.', ',']) then
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
begin
// ... but only if there are 3 numerical digits in between
@ -1573,8 +1572,8 @@ begin
fs.DecimalSeparator := ','
else
fs.DecimalSeparator := '.';
ADecimalSeparator := fs.DecimalSeparator;
AThousandSeparator := fs.ThousandSeparator;
ADecimalSeparator := #0; // this indicates that there are no decimals
done := true;
i := 0;
end else

View File

@ -65,7 +65,8 @@ type
// Test word wrapping
procedure TestWriteRead_WordWrap(AFormat: TsSpreadsheetFormat);
// Test number formats
procedure TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat);
procedure TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat;
AVariant: Integer = 0);
// Repeat with date/times
procedure TestWriteRead_DateTimeFormats(AFormat: TsSpreadsheetFormat);
// Test merged cells
@ -137,13 +138,14 @@ type
procedure TestWriteRead_OOXML_WordWrap;
{ CSV Tests }
procedure TestWriteRead_CSV_NumberFormats;
procedure TestWriteRead_CSV_NumberFormats_0;
procedure TestWriteRead_CSV_NumberFormats_1;
end;
implementation
uses
TypInfo, fpsutils;
TypInfo, fpsutils, fpscsv;
const
FmtNumbersSheet = 'NumbersFormat'; //let's distinguish it from the regular numbers sheet
@ -165,14 +167,18 @@ var
i: Integer;
fs: TFormatSettings;
myworkbook: TsWorkbook;
ch: Char;
begin
// Set up norm - MUST match spreadsheet cells exactly
// The workbook uses a slightly modified copy of the DefaultFormatSettings
// We create a copy here in order to better define the predicted strings.
myWorkbook := TsWorkbook.Create;
fs := MyWorkbook.FormatSettings;
myWorkbook.Free;
try
fs := MyWorkbook.FormatSettings;
finally
myWorkbook.Free;
end;
// Numbers
SollNumbers[0] := 0.0;
@ -299,21 +305,33 @@ end;
{ --- Number format tests --- }
procedure TSpreadWriteReadFormatTests.TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat);
procedure TSpreadWriteReadFormatTests.TestWriteRead_NumberFormats(AFormat: TsSpreadsheetFormat;
AVariant: Integer = 0);
var
MyWorksheet: TsWorksheet;
MyWorkbook: TsWorkbook;
ActualString: String;
ExpectedString: String;
Row, Col: Integer;
TempFile: string; //write xls/xml to this file and read back from it
begin
{// Not needed: use workbook.writetofile with overwrite=true
if fileexists(TempFile) then
DeleteFile(TempFile);
}
// Write out all test values
MyWorkbook := TsWorkbook.Create;
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);
for Row := Low(SollNumbers) to High(SollNumbers) do
for Col := ord(Low(SollNumberFormats)) to ord(High(SollNumberFormats)) do
@ -343,17 +361,18 @@ begin
for Col := Low(SollNumberFormats) to High(SollNumberFormats) do
begin
ActualString := MyWorkSheet.ReadAsUTF8Text(Row,Col);
if (SollNumberStrings[Row,Col] <> ActualString) then
ExpectedString := SollNumberStrings[Row, Col];
if (ExpectedString <> ActualString) then
begin
if (AFormat = sfCSV) and (Row=5) and (Col=0) then
// CSV has an insignificant difference of tiny numbers in
// general format
ignore('Ignoring insignificant saved string mismatch, cell ' +
CellNotation(MyWorksheet,Row,Col) +
', expected: <' + SollNumberStrings[Row,Col] +
', expected: <' + ExpectedString +
'> but was: <' + ActualString + '>')
else
CheckEquals(SollNumberStrings[Row,Col], ActualString,
CheckEquals(ExpectedString, ActualString,
'Test saved string mismatch, cell '+CellNotation(MyWorkSheet,Row,Col));
end;
end;
@ -388,9 +407,14 @@ begin
TestWriteRead_NumberFormats(sfOOXML);
end;
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats;
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats_0;
begin
TestWriteRead_NumberFormats(sfCSV);
TestWriteRead_NumberFormats(sfCSV, 0);
end;
procedure TSpreadWriteReadFormatTests.TestWriteRead_CSV_NumberFormats_1;
begin
TestWriteRead_NumberFormats(sfCSV, 1);
end;