
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8126 8e941d3f-bd1b-0410-a28a-d453659cc2b4
520 lines
16 KiB
ObjectPascal
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.
|
|
|