diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2022-05-06 09:43:22 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2022-05-10 16:23:52 +0200 |
commit | dce09d33aabfbad405f1accf02c14f8e85da8f6d (patch) | |
tree | af8484c55a2bb702a575a1e833a8371b657bd4eb | |
parent | 80606b89bbd38f63423eccfac4d1b8e6732b9560 (diff) |
add tests of query iterator's BinarySearch()
The BinarySeach() function is rather strange/dumb. If it doesn't
find the value, it tries to use the last previous value (i.e. it
additionally does the fixing up that VLOOKUP, MATCH, etc.) do.
At the some time, if there's a range of equal values, it doesn't
find the last one (and so callers need to fix that up). Write
some tests for that before I start touching the algorithm.
Change-Id: Ife2388acad691cce7ffaf5490fa74b5a3d453926
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134097
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r-- | sc/qa/unit/ucalc_sort.cxx | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/sc/qa/unit/ucalc_sort.cxx b/sc/qa/unit/ucalc_sort.cxx index 777a8edcf441..ca4b9c319e80 100644 --- a/sc/qa/unit/ucalc_sort.cxx +++ b/sc/qa/unit/ucalc_sort.cxx @@ -23,6 +23,7 @@ #include <scitems.hxx> #include <editutil.hxx> #include <drwlayer.hxx> +#include <queryiter.hxx> #include <editeng/wghtitem.hxx> #include <editeng/postitem.hxx> @@ -58,6 +59,7 @@ public: void testSortOutOfPlaceResult(); void testSortPartialFormulaGroup(); void testSortImages(); + void testQueryBinarySearch(); CPPUNIT_TEST_SUITE(TestSort); @@ -80,6 +82,7 @@ public: CPPUNIT_TEST(testSortOutOfPlaceResult); CPPUNIT_TEST(testSortPartialFormulaGroup); CPPUNIT_TEST(testSortImages); + CPPUNIT_TEST(testQueryBinarySearch); CPPUNIT_TEST_SUITE_END(); @@ -2019,6 +2022,190 @@ void TestSort::testSortImages() m_pDoc->DeleteTab(0); } +namespace +{ + +class TestQueryIterator + : public ScQueryCellIteratorBase< ScQueryCellIteratorAccess::Direct, ScQueryCellIteratorType::Generic > +{ + typedef ScQueryCellIteratorBase< ScQueryCellIteratorAccess::Direct, ScQueryCellIteratorType::Generic > Base; +public: + TestQueryIterator( ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable, + const ScQueryParam& aParam, bool bMod ) + : Base( rDocument, rContext, nTable, aParam, bMod ) + { + } + using Base::BinarySearch; // make public + SCROW GetRow() const { return nRow; } +}; + +ScQueryParam makeSearchParam( const ScRange& range, SCCOL col, ScQueryOp op, double value ) +{ + ScQueryParam param; + param.nCol1 = param.nCol2 = col; + param.nRow1 = range.aStart.Row(); + param.nRow2 = range.aEnd.Row(); + param.nTab = 0; + ScQueryEntry& entry = param.GetEntry(0); + ScQueryEntry::Item& item = entry.GetQueryItem(); + entry.bDoQuery = true; + entry.eOp = op; + item.mfVal = value; + item.meType = ScQueryEntry::ByValue; + return param; +} + +} // namespace + +void TestSort::testQueryBinarySearch() +{ + m_pDoc->InsertTab(0, "testQueryBinarySearch"); + + const ScAddress formulaAddress( 10, 0, 0 ); + ScRange range; + SCCOL ascendingCol; + SCCOL descendingCol; + OUString ascendingRangeName; + OUString descendingRangeName; + { + const std::vector<std::vector<const char*>> data = { + { "1", "9" }, // 0 + { "2", "9" }, // 1 + { "4", "5" }, // 2 + { "5", "5" }, // 3 + { "5", "5" }, // 4 + { "5", "5" }, // 5 + { "5", "5" }, // 6 + { "5", "4" }, // 7 + { "5", "4" }, // 8 + { "9", "2" }, // 9 + { "9", "1" }, // 10 + }; + ascendingCol = 0; + descendingCol = 1; + ascendingRangeName = u"$A$1:$A$" + OUString::number(data.size()); + descendingRangeName = u"$B$1:$B$" + OUString::number(data.size()); + + ScAddress pos(0,0,0); + range = insertRangeData(m_pDoc, pos, data); + CPPUNIT_ASSERT_EQUAL( ScRange( 0, 0, 0, data[ 0 ].size() - 1, data.size() - 1, 0 ), range ); + } + + { + // This should return the last 5. + m_pDoc->SetFormula( formulaAddress, "=MATCH(5;" + ascendingRangeName + ";1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, ascendingCol, SC_LESS_EQUAL, 5 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(8), it.GetRow()); + } + + { + // Descending, this should return the last 5. + m_pDoc->SetFormula( formulaAddress, "=MATCH(5;" + descendingRangeName + ";-1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, descendingCol, SC_GREATER_EQUAL, 5 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(6), it.GetRow()); + } + + { + // There's no 6, so this should return the last 5. + m_pDoc->SetFormula( formulaAddress, "=MATCH(6;" + ascendingRangeName + ";1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, ascendingCol, SC_LESS_EQUAL, 6 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(8), it.GetRow()); + } + + { + // Descending, there's no 6, so this should return the last 9. + m_pDoc->SetFormula( formulaAddress, "=MATCH(6;" + descendingRangeName + ";-1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, descendingCol, SC_GREATER_EQUAL, 6 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(1), it.GetRow()); + } + + { + // All values are larger than 0, so this should be an error. + m_pDoc->SetFormula( formulaAddress, "=MATCH(0;" + ascendingRangeName + ";1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( FormulaError::NotAvailable, m_pDoc->GetErrCode( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, ascendingCol, SC_LESS_EQUAL, 0 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + CPPUNIT_ASSERT_EQUAL(SCROW(0), it.GetRow()); + } + + { + // Descending, all values are larger than 0, so this should return the last item. + m_pDoc->SetFormula( formulaAddress, "=MATCH(0;" + descendingRangeName + ";-1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( 11.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, descendingCol, SC_GREATER_EQUAL, 0 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + CPPUNIT_ASSERT_EQUAL(SCROW(10), it.GetRow()); + } + + { + // All values are smaller than 10, so this should return the last item. + m_pDoc->SetFormula( formulaAddress, "=MATCH(10;" + ascendingRangeName + ";1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( 11.0, m_pDoc->GetValue( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, ascendingCol, SC_LESS_EQUAL, 10 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(10), it.GetRow()); + } + + { + // Descending, all values are smaller than 10, so this should be an error. + m_pDoc->SetFormula( formulaAddress, "=MATCH(10;" + descendingRangeName + ";-1)", + formula::FormulaGrammar::GRAM_NATIVE_UI); + CPPUNIT_ASSERT_EQUAL( FormulaError::NotAvailable, m_pDoc->GetErrCode( formulaAddress )); + + ScQueryParam param = makeSearchParam( range, descendingCol, SC_GREATER_EQUAL, 10 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + CPPUNIT_ASSERT_EQUAL(SCROW(0), it.GetRow()); + } + + { + // Search as ascending but use descending range (=search will not work). + ScQueryParam param = makeSearchParam( range, descendingCol, SC_LESS_EQUAL, 1 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(10), it.GetRow()); + } + + { + // Search as descending but use ascending range (=search will not work). + ScQueryParam param = makeSearchParam( range, ascendingCol, SC_GREATER_EQUAL, 9 ); + TestQueryIterator it( *m_pDoc, m_pDoc->GetNonThreadedContext(), 0, param, false ); + CPPUNIT_ASSERT(it.BinarySearch()); + // CPPUNIT_ASSERT_EQUAL(SCROW(10), it.GetRow()); + } + + m_pDoc->DeleteTab(0); +} + CPPUNIT_TEST_SUITE_REGISTRATION(TestSort); CPPUNIT_PLUGIN_IMPLEMENT(); |