lazarus-ccr/components/fpspreadsheet/unit-tests/common/sortingtests.pas
wp_xxyyzz 1626e8ab2f fpspreadsheet: Less hints and warnings
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8126 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2021-10-27 16:14:40 +00:00

520 lines
16 KiB
ObjectPascal

unit sortingtests;
{$mode objfpc}{$H+}
interface
{ Tests for sorting cells
}
uses
// Not using Lazarus package as the user may be working with multiple versions
// Instead, add .. to unit search path
Classes, SysUtils, fpcunit, testregistry,
fpstypes, fpspreadsheet, xlsbiff2, xlsbiff5, xlsbiff8, fpsopendocument, {and a project requirement for lclbase for utf8 handling}
testsutility;
var
// Norm to test against - list of numbers and strings that will be sorted
SollSortNumbers: array[0..9] of Double;
SollSortStrings: array[0..9] of String;
CommentIsSortedToStringIndex: Integer;
CommentIsSortedToNumberIndex: Integer;
HyperlinkIsSortedToStringIndex: Integer;
HyperlinkIsSortedToNumberIndex: Integer;
procedure InitUnsortedData;
type
{ TSpreadSortingTests }
TSpreadSortingTests = class(TTestCase)
private
protected
// Set up expected values:
procedure SetUp; override;
procedure TearDown; override;
procedure Test_Sorting_1( // one column or row
ASortByCols: Boolean;
ADescending: Boolean; // true: desending order
AWhat: Integer // What = 0: number, 1: strings, 2: mixed
);
procedure Test_Sorting_2( // two columns/rows, primary keys equal
ASortByCols: Boolean;
ADescending: Boolean
);
published
procedure Test_SortingByCols1_Numbers_Asc;
procedure Test_SortingByCols1_Numbers_Desc;
procedure Test_SortingByCols1_Strings_Asc;
procedure Test_SortingByCols1_Strings_Desc;
procedure Test_SortingByCols1_NumbersStrings_Asc;
procedure Test_SortingByCols1_NumbersStrings_Desc;
procedure Test_SortingByRows1_Numbers_Asc;
procedure Test_SortingByRows1_Numbers_Desc;
procedure Test_SortingByRows1_Strings_Asc;
procedure Test_SortingByRows1_Strings_Desc;
procedure Test_SortingByRows1_NumbersStrings_Asc;
procedure Test_SortingByRows1_NumbersStrings_Desc;
procedure Test_SortingByCols2_Asc;
procedure Test_SortingByCols2_Desc;
procedure Test_SortingByRows2_Asc;
procedure Test_SortingByRows2_Desc;
end;
implementation
uses
fpsutils;
const
SortingTestSheet = 'Sorting';
procedure InitUnsortedData;
// The logics of the detection requires equal count of numbers and strings.
begin
// When sorted the value is equal to the index
SollSortNumbers[0] := 9; // --> A1 --> will contain comment and hyperlink
SollSortNumbers[1] := 8;
SollSortNumbers[2] := 5;
SollSortNumbers[3] := 2;
SollSortNumbers[4] := 6;
SollSortNumbers[5] := 7;
SollSortNumbers[6] := 1;
SollSortNumbers[7] := 3;
SollSortNumbers[8] := 4;
SollSortNumbers[9] := 0;
CommentIsSortedToNumberIndex := 9;
HyperlinkIsSortedToNumberIndex := 9;
// When sorted the value is equal to 'A' + index
SollSortStrings[0] := 'C'; // --> Ar --> will contain hyperlink and comment
SollSortStrings[1] := 'G';
SollSortStrings[2] := 'F';
SollSortStrings[3] := 'I';
SollSortStrings[4] := 'B';
SollSortStrings[5] := 'D';
SollSortStrings[6] := 'J';
SollSortStrings[7] := 'H';
SollSortStrings[8] := 'E';
SollSortStrings[9] := 'A';
CommentIsSortedToStringIndex := 2;
HyperlinkIsSortedToStringIndex := 2;
end;
{ TSpreadSortingTests }
procedure TSpreadSortingTests.SetUp;
begin
inherited SetUp;
InitUnsortedData;
end;
procedure TSpreadSortingTests.TearDown;
begin
inherited TearDown;
end;
procedure TSpreadSortingTests.Test_Sorting_1(ASortByCols: Boolean;
ADescending: Boolean; AWhat: Integer);
const
AFormat = sfExcel8;
var
MyWorksheet: TsWorksheet;
MyWorkbook: TsWorkbook;
i, ilast, row, col: Integer;
TempFile: string; //write xls/xml to this file and read back from it
sortParams: TsSortParams;
actualNumber: Double;
actualString: String;
expectedNumber: Double;
expectedString: String;
cell: PCell;
begin
sortParams := InitSortParams(ASortByCols, 1);
TempFile := GetTempFileName;
MyWorkbook := TsWorkbook.Create;
try
MyWorkSheet:= MyWorkBook.AddWorksheet(SortingTestSheet);
col := 0;
row := 0;
if ASortByCols then begin
case AWhat of
0: for i :=0 to High(SollSortNumbers) do // Numbers only
MyWorksheet.WriteNumber(i, col, SollSortNumbers[i]);
1: for i := 0 to High(SollSortStrings) do // Strings only
Myworksheet.WriteText(i, col, SollSortStrings[i]);
2: begin // Numbers and strings
for i := 0 to High(SollSortNumbers) do
MyWorkSheet.WriteNumber(i*2, col, SollSortNumbers[i]);
for i := 0 to High(SollSortStrings) do
MyWorksheet.WriteText(i*2+1, col, SollSortStrings[i]);
end;
end
end
else begin
case AWhat of
0: for i := 0 to High(SollSortNumbers) do
MyWorksheet.WriteNumber(row, i, SollSortNumbers[i]);
1: for i := 0 to High(SollSortStrings) do
MyWorksheet.WriteText(row, i, SollSortStrings[i]);
2: begin
for i := 0 to High(SollSortNumbers) do
myWorkSheet.WriteNumber(row, i*2, SollSortNumbers[i]);
for i:=0 to High(SollSortStrings) do
MyWorksheet.WriteText(row, i*2+1, SollSortStrings[i]);
end;
end;
end;
// Add comment and hyperlink to cell A1. After sorting it is expected
// in cell defined by CommentIsSortedToXXXIndex (XXX = Number/String)
if AFormat <> sfExcel8 then // Comments not implemented for writing Excel8
{%H-}MyWorksheet.WriteComment(0, 0, 'Test comment');
MyWorksheet.WriteHyperlink(0, 0, 'http://www.google.com');
MyWorkBook.WriteToFile(TempFile, AFormat, true);
finally
MyWorkbook.Free;
end;
MyWorkbook := TsWorkbook.Create;
try
// Read spreadsheet file...
MyWorkbook.ReadFromFile(TempFile, AFormat);
if AFormat = sfExcel2 then
{%H-}MyWorksheet := MyWorkbook.GetFirstWorksheet
else
MyWorksheet := GetWorksheetByName(MyWorkBook, SortingTestSheet);
if MyWorksheet = nil then
fail('Error in test code. Failed to get named worksheet');
// ... set up sorting direction
case ADescending of
false: sortParams.Keys[0].Options := []; // Ascending sort
true : sortParams.Keys[0].Options := [ssoDescending]; // Descending sort
end;
// ... and sort it.
case AWhat of
0: iLast:= High(SollSortNumbers);
1: iLast := High(SollSortStrings);
2: iLast := Length(SollSortNumbers) + Length(SollSortStrings) - 1;
end;
if ASortByCols then
MyWorksheet.Sort(sortParams, 0, 0, iLast, 0)
else
MyWorksheet.Sort(sortParams, 0, 0, 0, iLast);
// for debugging, to see the sorted data
//MyWorkbook.WriteToFile('sorted.xls', AFormat, true);
row := 0;
col := 0;
for i:=0 to iLast do
begin
if ASortByCols then
case ADescending of
false: row := i; // ascending
true : row := iLast - i; // descending
end
else
case ADescending of
false: col := i; // ascending
true : col := iLast - i; // descending
end;
case AWhat of
0: begin
cell := MyWorksheet.FindCell(row, col);
actualNumber := MyWorksheet.ReadAsNumber(cell);
expectedNumber := i;
CheckEquals(expectednumber, actualnumber,
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
if AFormat <> sfExcel8 then // Comments are not written for sfExcel8 --> ignore
{%H-}CheckEquals(
i=CommentIsSortedToNumberIndex,
MyWorksheet.HasComment(cell),
'Sorted comment position mismatch, cell '+CellNotation(MyWorksheet, row, col));
CheckEquals(
i = HyperlinkisSortedToNumberIndex,
MyWorksheet.HasHyperlink(cell),
'Sorted hyperlink position mismatch, cell '+CellNotation(MyWorksheet, row, col));
end;
1: begin
cell := MyWorksheet.FindCell(row, col);
actualString := MyWorksheet.ReadAsText(cell);
expectedString := char(ord('A') + i);
CheckEquals(expectedstring, actualstring,
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
if AFormat <> sfExcel8 then // Comments are not written for sfExcel8 --> ignore
{%H-}CheckEquals(
i=CommentIsSortedToStringIndex,
MyWorksheet.HasComment(cell),
'Sorted comment position mismatch, cell '+CellNotation(MyWorksheet, row, col));
CheckEquals(
i = HyperlinkisSortedToStringIndex,
MyWorksheet.HasHyperlink(cell),
'Sorted hyperlink position mismatch, cell '+CellNotation(MyWorksheet, row, col));
end;
2: begin // with increasing i, we see first the numbers, then the strings
if i <= High(SollSortNumbers) then begin
cell := MyWorksheet.FindCell(row, col);
actualnumber := MyWorksheet.ReadAsNumber(cell);
expectedNumber := i;
CheckEquals(expectednumber, actualnumber,
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
end else begin
actualstring := MyWorksheet.ReadAsText(row, col);
expectedstring := char(ord('A') + i - Length(SollSortNumbers));
CheckEquals(expectedstring, actualstring,
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
end;
end;
end;
end;
finally
MyWorkbook.Free;
end;
DeleteFile(TempFile);
end;
procedure TSpreadSortingTests.Test_Sorting_2(ASortByCols: Boolean;
ADescending: Boolean);
const
AFormat = sfExcel8;
var
MyWorksheet: TsWorksheet;
MyWorkbook: TsWorkbook;
i, ilast, row, col: Integer;
TempFile: string; //write xls/xml to this file and read back from it
sortParams: TsSortParams;
actualNumber: Double;
actualString: String;
expectedNumber: Double;
expectedString: String;
begin
sortParams := InitSortParams(ASortByCols, 2);
sortParams.Keys[0].ColRowIndex := 0; // col/row 0 is primary key
sortParams.Keys[1].ColRowIndex := 1; // col/row 1 is second key
iLast := High(SollSortNumbers);
TempFile := GetTempFileName;
MyWorkbook := TsWorkbook.Create;
try
MyWorkSheet:= MyWorkBook.AddWorksheet(SortingTestSheet);
col := 0;
row := 0;
if ASortByCols then
begin
// Write all randomized numbers to column B
for i:=0 to iLast do
MyWorksheet.WriteNumber(i, col+1, SollSortNumbers[i]);
// divide each number by 2 and calculate the character assigned to it
// and write it to column A
// We will sort primarily according to column A, and seconarily according
// to B. The construction allows us to determine if the sorting is correct.
for i:=0 to iLast do
MyWorksheet.WriteText(i, col, char(ord('A')+round(SollSortNumbers[i]) div 2));
end else
begin
// The same with the rows...
for i:=0 to iLast do
MyWorksheet.WriteNumber(row+1, i, SollSortNumbers[i]);
for i:=0 to iLast do
MyWorksheet.WriteText(row, i, char(ord('A')+round(SollSortNumbers[i]) div 2));
end;
MyWorkBook.WriteToFile(TempFile, AFormat, true);
finally
MyWorkbook.Free;
end;
MyWorkbook := TsWorkbook.Create;
try
// Read spreadsheet file...
MyWorkbook.ReadFromFile(TempFile, AFormat);
if AFormat = sfExcel2 then
{%H-}MyWorksheet := MyWorkbook.GetFirstWorksheet
else
MyWorksheet := GetWorksheetByName(MyWorkBook, SortingTestSheet);
if MyWorksheet = nil then
fail('Error in test code. Failed to get named worksheet');
// ... set up sort direction
if ADescending then
begin
sortParams.Keys[0].Options := [ssoDescending];
sortParams.Keys[1].Options := [ssoDescending];
end else
begin
sortParams.Keys[0].Options := [];
sortParams.Keys[1].Options := [];
end;
// ... and sort it.
if ASortByCols then
MyWorksheet.Sort(sortParams, 0, 0, iLast, 1)
else
MyWorksheet.Sort(sortParams, 0, 0, 1, iLast);
// for debugging, to see the sorted data
// MyWorkbook.WriteToFile('sorted.xls', AFormat, true);
for i:=0 to iLast do
begin
if ASortByCols then
begin
// Read the number first, they must be in order 0...9 (if ascending).
col := 1;
case ADescending of
false : row := i;
true : row := iLast - i;
end;
actualNumber := MyWorksheet.ReadAsNumber(row, col); // col B is the number, must be 0...9 here
expectedNumber := i;
CheckEquals(expectednumber, actualnumber,
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
// Now read the string. It must be the character corresponding to the
// half of the number
col := 0;
actualString := MyWorksheet.ReadAsText(row, col);
expectedString := char(ord('A') + round(expectedNumber) div 2);
CheckEquals(expectedstring, actualstring,
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
end else
begin
row := 1;
case ADescending of
false : col := i;
true : col := iLast - i;
end;
actualNumber := MyWorksheet.ReadAsNumber(row, col);
expectedNumber := i;
CheckEquals(expectednumber, actualnumber,
'Sorted cell number mismatch, cell '+CellNotation(MyWorksheet, row, col));
row := 0;
actualstring := MyWorksheet.ReadAsText(row, col);
expectedString := char(ord('A') + round(expectedNumber) div 2);
CheckEquals(expectedstring, actualstring,
'Sorted cell string mismatch, cell '+CellNotation(MyWorksheet, row, col));
end;
end;
finally
MyWorkbook.Free;
end;
DeleteFile(TempFile);
end;
{ Sort 1 column }
procedure TSpreadSortingTests.Test_SortingByCols1_Numbers_ASC;
begin
Test_Sorting_1(true, false, 0);
end;
procedure TSpreadSortingTests.Test_SortingByCols1_Numbers_DESC;
begin
Test_Sorting_1(true, true, 0);
end;
procedure TSpreadSortingTests.Test_SortingByCols1_Strings_ASC;
begin
Test_Sorting_1(true, false, 1);
end;
procedure TSpreadSortingTests.Test_SortingByCols1_Strings_DESC;
begin
Test_Sorting_1(true, true, 1);
end;
procedure TSpreadSortingTests.Test_SortingByCols1_NumbersStrings_ASC;
begin
Test_Sorting_1(true, false, 2);
end;
procedure TSpreadSortingTests.Test_SortingByCols1_NumbersStrings_DESC;
begin
Test_Sorting_1(true, true, 2);
end;
{ Sort 1 row }
procedure TSpreadSortingTests.Test_SortingByRows1_Numbers_asc;
begin
Test_Sorting_1(false, false, 0);
end;
procedure TSpreadSortingTests.Test_SortingByRows1_Numbers_Desc;
begin
Test_Sorting_1(false, true, 0);
end;
procedure TSpreadSortingTests.Test_SortingByRows1_Strings_Asc;
begin
Test_Sorting_1(false, false, 1);
end;
procedure TSpreadSortingTests.Test_SortingByRows1_Strings_Desc;
begin
Test_Sorting_1(false, true, 1);
end;
procedure TSpreadSortingTests.Test_SortingByRows1_NumbersStrings_Asc;
begin
Test_Sorting_1(false, false, 2);
end;
procedure TSpreadSortingTests.Test_SortingByRows1_NumbersStrings_Desc;
begin
Test_Sorting_1(false, true, 2);
end;
{ two columns }
procedure TSpreadSortingTests.Test_SortingByCols2_Asc;
begin
Test_Sorting_2(true, false);
end;
procedure TSpreadSortingTests.Test_SortingByCols2_Desc;
begin
Test_Sorting_2(true, true);
end;
procedure TSpreadSortingTests.Test_SortingByRows2_Asc;
begin
Test_Sorting_2(false, false);
end;
procedure TSpreadSortingTests.Test_SortingByRows2_Desc;
begin
Test_Sorting_2(false, true);
end;
initialization
RegisterTest(TSpreadSortingTests);
InitUnsortedData;
end.