/** @file testRunStyles.cxx ** Unit Tests for Scintilla internal data structures **/ #include #include #include #include #include #include #include #include #include "Debugging.h" #include "Position.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "catch.hpp" using namespace Scintilla::Internal; // Test RunStyles. using UniqueInt = std::unique_ptr; TEST_CASE("CompileCopying RunStyles") { // These are compile-time tests to check that basic copy and move // operations are defined correctly. SECTION("CopyingMoving") { RunStyles s; RunStyles s2; // Copy constructor RunStyles sa(s); // Copy assignment fails RunStyles sb; sb = s; // Move constructor RunStyles sc(std::move(s)); // Move assignment RunStyles sd; sd = (std::move(s2)); } #if defined(SHOW_COPY_BUILD_FAILURES) // It should be reasonable to instantiate RunStyles where STYLE is move-only but fails SECTION("MoveOnly") { RunStyles s; // Copy is not defined for std::unique_ptr // Copy constructor fails RunStyles sa(s); // Copy assignment fails RunStyles sb; sb = s; // Move constructor fails RunStyles sc(std::move(s)); // Move assignment fails RunStyles sd; sd = (std::move(s)); } #endif } namespace Scintilla::Internal { // Xcode clang 9.0 doesn't like this when in the unnamed namespace bool operator==(const FillResult &fra, const FillResult &frb) { return fra.changed == frb.changed && fra.position == frb.position && fra.fillLength == frb.fillLength; } } TEST_CASE("RunStyles") { RunStyles rs; SECTION("IsEmptyInitially") { REQUIRE(0 == rs.Length()); REQUIRE(1 == rs.Runs()); } SECTION("SimpleInsert") { rs.InsertSpace(0, 1); REQUIRE(1 == rs.Length()); REQUIRE(1 == rs.Runs()); REQUIRE(0 == rs.ValueAt(0)); REQUIRE(1 == rs.FindNextChange(0, rs.Length())); REQUIRE(2 == rs.FindNextChange(1, rs.Length())); } SECTION("TwoRuns") { rs.InsertSpace(0, 2); REQUIRE(2 == rs.Length()); REQUIRE(1 == rs.Runs()); rs.SetValueAt(0, 2); REQUIRE(2 == rs.Runs()); REQUIRE(2 == rs.ValueAt(0)); REQUIRE(0 == rs.ValueAt(1)); REQUIRE(1 == rs.FindNextChange(0, rs.Length())); REQUIRE(2 == rs.FindNextChange(1, rs.Length())); REQUIRE(3 == rs.FindNextChange(2, rs.Length())); } SECTION("LongerRuns") { rs.InsertSpace(0, 5); rs.SetValueAt(0, 3); rs.SetValueAt(1, 3); REQUIRE(3 == rs.ValueAt(0)); REQUIRE(3 == rs.ValueAt(1)); REQUIRE(0 == rs.ValueAt(2)); REQUIRE(2 == rs.Runs()); REQUIRE(0 == rs.StartRun(0)); REQUIRE(2 == rs.EndRun(0)); REQUIRE(0 == rs.StartRun(1)); REQUIRE(2 == rs.EndRun(1)); REQUIRE(2 == rs.StartRun(2)); REQUIRE(5 == rs.EndRun(2)); REQUIRE(2 == rs.StartRun(3)); REQUIRE(5 == rs.EndRun(3)); REQUIRE(2 == rs.StartRun(4)); REQUIRE(5 == rs.EndRun(4)); // At end REQUIRE(2 == rs.StartRun(5)); REQUIRE(5 == rs.EndRun(5)); // After end is same as end REQUIRE(2 == rs.StartRun(6)); REQUIRE(5 == rs.EndRun(6)); REQUIRE(2 == rs.FindNextChange(0, rs.Length())); REQUIRE(5 == rs.FindNextChange(2, rs.Length())); REQUIRE(6 == rs.FindNextChange(5, rs.Length())); } SECTION("FillRange") { rs.InsertSpace(0, 5); int startFill = 1; int lengthFill = 3; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 1, 3} == fr); REQUIRE(0 == rs.ValueAt(0)); REQUIRE(99 == rs.ValueAt(1)); REQUIRE(99 == rs.ValueAt(2)); REQUIRE(99 == rs.ValueAt(3)); REQUIRE(0 == rs.ValueAt(4)); REQUIRE(0 == rs.StartRun(0)); REQUIRE(1 == rs.EndRun(0)); REQUIRE(1 == rs.StartRun(1)); REQUIRE(4 == rs.EndRun(1)); } SECTION("FillRangeAlreadyFilled") { rs.InsertSpace(0, 5); int startFill = 1; int lengthFill = 3; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 1, 3} == fr); int startFill2 = 2; int lengthFill2 = 1; // Compiler warnings if 'false' used instead of '0' as expected value: const auto fr2 = rs.FillRange(startFill2, 99, lengthFill2); REQUIRE(FillResult{false, 2, 1} == fr2); REQUIRE(0 == rs.ValueAt(0)); REQUIRE(99 == rs.ValueAt(1)); REQUIRE(99 == rs.ValueAt(2)); REQUIRE(99 == rs.ValueAt(3)); REQUIRE(0 == rs.ValueAt(4)); REQUIRE(3 == rs.Runs()); } SECTION("FillRangeAlreadyPartFilled") { rs.InsertSpace(0, 5); int startFill = 1; int lengthFill = 2; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 1, 2} == fr); int startFill2 = 2; int lengthFill2 = 2; const auto fr2 = rs.FillRange(startFill2, 99, lengthFill2); REQUIRE(FillResult{true, 3, 1} == fr2); REQUIRE(3 == rs.Runs()); } SECTION("DeleteRange") { rs.InsertSpace(0, 5); rs.SetValueAt(0, 3); REQUIRE(2 == rs.Runs()); rs.SetValueAt(1, 3); REQUIRE(2 == rs.Runs()); rs.DeleteRange(1, 1); REQUIRE(4 == rs.Length()); REQUIRE(2 == rs.Runs()); REQUIRE(3 == rs.ValueAt(0)); REQUIRE(0 == rs.ValueAt(1)); REQUIRE(0 == rs.StartRun(0)); REQUIRE(1 == rs.EndRun(0)); REQUIRE(1 == rs.StartRun(1)); REQUIRE(4 == rs.EndRun(1)); REQUIRE(1 == rs.StartRun(2)); REQUIRE(4 == rs.EndRun(2)); } SECTION("Find") { rs.InsertSpace(0, 5); int startFill = 1; int lengthFill = 3; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 1, 3} == fr); REQUIRE(0 == rs.Find(0,0)); REQUIRE(1 == rs.Find(99,0)); REQUIRE(-1 == rs.Find(3,0)); REQUIRE(4 == rs.Find(0,1)); REQUIRE(1 == rs.Find(99,1)); REQUIRE(-1 == rs.Find(3,1)); REQUIRE(4 == rs.Find(0,2)); REQUIRE(2 == rs.Find(99,2)); REQUIRE(-1 == rs.Find(3, 2)); REQUIRE(4 == rs.Find(0,4)); REQUIRE(-1 == rs.Find(99,4)); REQUIRE(-1 == rs.Find(3,4)); REQUIRE(-1 == rs.Find(0,5)); REQUIRE(-1 == rs.Find(99,5)); REQUIRE(-1 == rs.Find(3,5)); REQUIRE(-1 == rs.Find(0,6)); REQUIRE(-1 == rs.Find(99,6)); REQUIRE(-1 == rs.Find(3,6)); } SECTION("AllSame") { REQUIRE(true == rs.AllSame()); rs.InsertSpace(0, 5); REQUIRE(true == rs.AllSame()); REQUIRE(false == rs.AllSameAs(88)); REQUIRE(true == rs.AllSameAs(0)); int startFill = 1; int lengthFill = 3; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(true == fr.changed); REQUIRE(false == rs.AllSame()); REQUIRE(false == rs.AllSameAs(88)); REQUIRE(false == rs.AllSameAs(0)); const auto fr2 = rs.FillRange(startFill, 0, lengthFill); REQUIRE(true == fr2.changed); REQUIRE(true == rs.AllSame()); REQUIRE(false == rs.AllSameAs(88)); REQUIRE(true == rs.AllSameAs(0)); } SECTION("FindWithReversion") { rs.InsertSpace(0, 5); REQUIRE(1 == rs.Runs()); int startFill = 1; int lengthFill = 1; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 1, 1} == fr); REQUIRE(3 == rs.Runs()); startFill = 2; lengthFill = 1; const auto fr2 = rs.FillRange(startFill, 99, lengthFill); REQUIRE(FillResult{true, 2, 1} == fr2); REQUIRE(3 == rs.Runs()); startFill = 1; lengthFill = 1; const auto fr3 = rs.FillRange(startFill, 0, lengthFill); REQUIRE(FillResult{true, 1, 1} == fr3); REQUIRE(3 == rs.Runs()); startFill = 2; lengthFill = 1; const auto fr4 = rs.FillRange(startFill, 0, lengthFill); REQUIRE(FillResult{true, 2, 1} == fr4); REQUIRE(1 == rs.Runs()); REQUIRE(-1 == rs.Find(0,6)); } SECTION("FinalRunInversion") { REQUIRE(1 == rs.Runs()); rs.InsertSpace(0, 1); REQUIRE(1 == rs.Runs()); rs.SetValueAt(0, 1); REQUIRE(1 == rs.Runs()); rs.InsertSpace(1, 1); REQUIRE(1 == rs.Runs()); rs.SetValueAt(1, 1); REQUIRE(1 == rs.Runs()); rs.SetValueAt(1, 0); REQUIRE(2 == rs.Runs()); rs.SetValueAt(1, 1); REQUIRE(1 == rs.Runs()); } SECTION("DeleteAll") { rs.InsertSpace(0, 5); rs.SetValueAt(0, 3); rs.SetValueAt(1, 3); rs.DeleteAll(); REQUIRE(0 == rs.Length()); REQUIRE(0 == rs.ValueAt(0)); REQUIRE(1 == rs.Runs()); } SECTION("DeleteSecond") { rs.InsertSpace(0, 3); int startFill = 1; int lengthFill = 1; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(true == fr.changed); REQUIRE(3 == rs.Length()); REQUIRE(3 == rs.Runs()); rs.DeleteRange(1, 1); REQUIRE(2 == rs.Length()); REQUIRE(1 == rs.Runs()); } SECTION("DeleteEndRun") { rs.InsertSpace(0, 2); int startFill = 1; int lengthFill = 1; const auto fr = rs.FillRange(startFill, 99, lengthFill); REQUIRE(true == fr.changed); REQUIRE(2 == rs.Length()); REQUIRE(2 == rs.Runs()); REQUIRE(0 == rs.StartRun(0)); REQUIRE(1 == rs.EndRun(0)); REQUIRE(1 == rs.StartRun(1)); REQUIRE(2 == rs.EndRun(1)); rs.DeleteRange(1, 1); REQUIRE(1 == rs.Length()); REQUIRE(1 == rs.Runs()); REQUIRE(0 == rs.StartRun(0)); REQUIRE(1 == rs.EndRun(0)); REQUIRE(0 == rs.StartRun(1)); REQUIRE(1 == rs.EndRun(1)); rs.Check(); } SECTION("OutsideBounds") { rs.InsertSpace(0, 1); int startFill = 1; int lengthFill = 1; rs.FillRange(startFill, 99, lengthFill); REQUIRE(1 == rs.Length()); REQUIRE(1 == rs.Runs()); REQUIRE(0 == rs.StartRun(0)); REQUIRE(1 == rs.EndRun(0)); } }