diff options
| -rw-r--r-- | src/CellBuffer.h | 1 | ||||
| -rw-r--r-- | src/Document.cxx | 7 | ||||
| -rw-r--r-- | src/Document.h | 1 | ||||
| -rw-r--r-- | src/PerLine.cxx | 37 | ||||
| -rw-r--r-- | src/PerLine.h | 5 | ||||
| -rw-r--r-- | test/unit/UnitTester.vcxproj | 1 | ||||
| -rw-r--r-- | test/unit/makefile | 3 | ||||
| -rw-r--r-- | test/unit/test.mak | 3 | ||||
| -rw-r--r-- | test/unit/testPerLine.cxx | 363 | 
9 files changed, 418 insertions, 3 deletions
| diff --git a/src/CellBuffer.h b/src/CellBuffer.h index 5138fd0aa..3e16bcdc8 100644 --- a/src/CellBuffer.h +++ b/src/CellBuffer.h @@ -16,6 +16,7 @@ public:  	virtual ~PerLine() {}  	virtual void Init()=0;  	virtual void InsertLine(Sci::Line line)=0; +	virtual void InsertLines(Sci::Line line, Sci::Line lines) = 0;  	virtual void RemoveLine(Sci::Line line)=0;  }; diff --git a/src/Document.cxx b/src/Document.cxx index 2382e1c21..ff009ee3e 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -178,6 +178,13 @@ void Document::InsertLine(Sci::Line line) {  	}  } +void Document::InsertLines(Sci::Line line, Sci::Line lines) { +	for (const auto &pl : perLineData) { +		if (pl) +			pl->InsertLines(line, lines); +	} +} +  void Document::RemoveLine(Sci::Line line) {  	for (const std::unique_ptr<PerLine> &pl : perLineData) {  		if (pl) diff --git a/src/Document.h b/src/Document.h index a1d9ff7c2..2ff0e8b27 100644 --- a/src/Document.h +++ b/src/Document.h @@ -298,6 +298,7 @@ public:  	// From PerLine  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	int LineEndTypesSupported() const; diff --git a/src/PerLine.cxx b/src/PerLine.cxx index 47556f3ae..c7204e31a 100644 --- a/src/PerLine.cxx +++ b/src/PerLine.cxx @@ -102,6 +102,12 @@ void LineMarkers::InsertLine(Sci::Line line) {  	}  } +void LineMarkers::InsertLines(Sci::Line line, Sci::Line lines) { +	if (markers.Length()) { +		markers.InsertEmpty(line, lines); +	} +} +  void LineMarkers::RemoveLine(Sci::Line line) {  	// Retain the markers from the deleted line by oring them into the previous line  	if (markers.Length()) { @@ -219,7 +225,14 @@ void LineLevels::Init() {  void LineLevels::InsertLine(Sci::Line line) {  	if (levels.Length()) {  		const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; -		levels.InsertValue(line, 1, level); +		levels.Insert(line, level); +	} +} + +void LineLevels::InsertLines(Sci::Line line, Sci::Line lines) { +	if (levels.Length()) { +		const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; +		levels.InsertValue(line, lines, level);  	}  } @@ -281,6 +294,14 @@ void LineState::InsertLine(Sci::Line line) {  	}  } +void LineState::InsertLines(Sci::Line line, Sci::Line lines) { +	if (lineStates.Length()) { +		lineStates.EnsureLength(line); +		const int val = (line < lineStates.Length()) ? lineStates[line] : 0; +		lineStates.InsertValue(line, lines, val); +	} +} +  void LineState::RemoveLine(Sci::Line line) {  	if (lineStates.Length() > line) {  		lineStates.Delete(line); @@ -343,6 +364,13 @@ void LineAnnotation::InsertLine(Sci::Line line) {  	}  } +void LineAnnotation::InsertLines(Sci::Line line, Sci::Line lines) { +	if (annotations.Length()) { +		annotations.EnsureLength(line); +		annotations.InsertEmpty(line, lines); +	} +} +  void LineAnnotation::RemoveLine(Sci::Line line) {  	if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {  		annotations[line-1].reset(); @@ -459,6 +487,13 @@ void LineTabstops::InsertLine(Sci::Line line) {  	}  } +void LineTabstops::InsertLines(Sci::Line line, Sci::Line lines) { +	if (tabstops.Length()) { +		tabstops.EnsureLength(line); +		tabstops.InsertEmpty(line, lines); +	} +} +  void LineTabstops::RemoveLine(Sci::Line line) {  	if (tabstops.Length() > line) {  		tabstops[line].reset(); diff --git a/src/PerLine.h b/src/PerLine.h index b6565fcc1..b43b0a18b 100644 --- a/src/PerLine.h +++ b/src/PerLine.h @@ -59,6 +59,7 @@ public:  	~LineMarkers() override;  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	int MarkValue(Sci::Line line) const noexcept; @@ -85,6 +86,7 @@ public:  	~LineLevels() override;  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	void ExpandLevels(Sci::Line sizeNew=-1); @@ -106,6 +108,7 @@ public:  	~LineState() override;  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	int SetLineState(Sci::Line line, int state); @@ -126,6 +129,7 @@ public:  	~LineAnnotation() override;  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	bool MultipleStyles(Sci::Line line) const noexcept; @@ -155,6 +159,7 @@ public:  	~LineTabstops() override;  	void Init() override;  	void InsertLine(Sci::Line line) override; +	void InsertLines(Sci::Line line, Sci::Line lines) override;  	void RemoveLine(Sci::Line line) override;  	bool ClearTabstops(Sci::Line line) noexcept; diff --git a/test/unit/UnitTester.vcxproj b/test/unit/UnitTester.vcxproj index 361f41083..65d4c58dc 100644 --- a/test/unit/UnitTester.vcxproj +++ b/test/unit/UnitTester.vcxproj @@ -155,6 +155,7 @@      <ClCompile Include="..\..\src\CharClassify.cxx" />
      <ClCompile Include="..\..\src\ContractionState.cxx" />
      <ClCompile Include="..\..\src\Decoration.cxx" />
 +    <ClCompile Include="..\..\src\PerLine.cxx" />
      <ClCompile Include="..\..\src\RunStyles.cxx" />
      <ClCompile Include="..\..\src\UniConversion.cxx" />
      <ClCompile Include="..\..\src\UniqueString.cxx" />
 diff --git a/test/unit/makefile b/test/unit/makefile index 6d5ead6cd..05bbed944 100644 --- a/test/unit/makefile +++ b/test/unit/makefile @@ -3,7 +3,7 @@  # On Windows g++ is used, on OS X clang, and on Linux G++ is used by default  # but clang can be used by defining CLANG when invoking make  # clang works only with libc++, not libstdc++ -# Tested with clang 3.3 and g++ 4.8 +# Tested with clang 9 and g++ 9  CXXSTD=c++17 @@ -54,6 +54,7 @@ TESTEDSRC=\   ../../src/CharClassify.cxx \   ../../src/ContractionState.cxx \   ../../src/Decoration.cxx \ + ../../src/PerLine.cxx \   ../../src/RunStyles.cxx \   ../../src/UniConversion.cxx \   ../../src/UniqueString.cxx diff --git a/test/unit/test.mak b/test/unit/test.mak index 42b17e556..6503acba4 100644 --- a/test/unit/test.mak +++ b/test/unit/test.mak @@ -1,5 +1,5 @@  # Build all the unit tests with Microsoft Visual C++ using nmake -# Tested with Visual C++ 2010 and 2013 +# Tested with Visual C++ 2019  DEL = del /q  EXE = unitTest.exe @@ -17,6 +17,7 @@ TESTEDSRC=\   ../../src/CharClassify.cxx \   ../../src/ContractionState.cxx \   ../../src/Decoration.cxx \ + ../../src/PerLine.cxx \   ../../src/RunStyles.cxx \   ../../src/UniConversion.cxx \   ../../src/UniqueString.cxx diff --git a/test/unit/testPerLine.cxx b/test/unit/testPerLine.cxx new file mode 100644 index 000000000..b2a84793d --- /dev/null +++ b/test/unit/testPerLine.cxx @@ -0,0 +1,363 @@ +// Unit Tests for Scintilla internal data structures + +#include <cstddef> +#include <cstring> +#include <stdexcept> +#include <string_view> +#include <vector> +#include <forward_list> +#include <algorithm> +#include <memory> + +#include "Platform.h" + +#include "Scintilla.h" +#include "Position.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "CellBuffer.h" +#include "PerLine.h" + +#include "catch.hpp" + +using namespace Scintilla; + +// Test MarkerHandleSet. + +TEST_CASE("MarkerHandleSet") { + +	MarkerHandleSet mhs; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(mhs.Empty()); +		REQUIRE(0 == mhs.MarkValue()); +		REQUIRE(!mhs.Contains(1)); +	} + +	SECTION("InsertDelete") { +		// Test knows that InsertHandle inserts at front (0) +		// Insert 1 with handle 100 +		REQUIRE(mhs.InsertHandle(100,1)); +		REQUIRE(!mhs.Empty()); +		REQUIRE(2 == mhs.MarkValue()); +		REQUIRE(mhs.Contains(100)); + +		// Insert 2 with handle 200 +		REQUIRE(mhs.InsertHandle(200,2)); +		REQUIRE(!mhs.Empty()); +		REQUIRE(mhs.Contains(100)); +		REQUIRE(mhs.Contains(200)); +		REQUIRE(6 == mhs.MarkValue()); + +		const MarkerHandleNumber *mhn0 = mhs.GetMarkerHandleNumber(0); +		REQUIRE(200 == mhn0->handle); +		REQUIRE(2 == mhn0->number); +		const MarkerHandleNumber *mhn1 = mhs.GetMarkerHandleNumber(1); +		REQUIRE(100 == mhn1->handle); +		REQUIRE(1 == mhn1->number); +		const MarkerHandleNumber *mhn2 = mhs.GetMarkerHandleNumber(2); +		REQUIRE(nullptr == mhn2); + +		// Remove first insertion +		mhs.RemoveHandle(100); +		REQUIRE(!mhs.Empty()); +		REQUIRE(mhs.Contains(200)); +		REQUIRE(4 == mhs.MarkValue()); + +		// Remove remaining element +		REQUIRE(mhs.RemoveNumber(2, true)); +		REQUIRE(mhs.Empty()); +		REQUIRE(!mhs.Contains(200)); +		REQUIRE(0 == mhs.MarkValue()); +	} + +	SECTION("Combine") { +		mhs.InsertHandle(100, 1); +		MarkerHandleSet mhsOther; +		mhsOther.InsertHandle(200, 2); +		mhs.CombineWith(&mhsOther); +		REQUIRE(mhsOther.Empty()); +		mhs.RemoveHandle(100); +		mhs.RemoveHandle(200); +		REQUIRE(mhs.Empty()); +	} +} + +TEST_CASE("LineMarkers") { + +	LineMarkers lm; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(0 == lm.MarkValue(0)); +	} + +	SECTION("AddDelete") { +		// Test knows the way handles are allocated, starting from 1 +		lm.InsertLines(0, 5); +		const int handle1 = lm.AddMark(0, 1, 5); +		REQUIRE(1 == handle1); +		REQUIRE(2 == lm.MarkValue(0)); +		REQUIRE(1 == lm.HandleFromLine(0, 0)); +		REQUIRE(1 == lm.NumberFromLine(0, 0)); +		REQUIRE(-1 == lm.HandleFromLine(0, 1)); +		REQUIRE(-1 == lm.NumberFromLine(0, 1)); +		REQUIRE(0 == lm.LineFromHandle(handle1)); + +		REQUIRE(lm.DeleteMark(0, 1, true)); +		REQUIRE(0 == lm.MarkValue(0)); + +		const int handle2 = lm.AddMark(0, 2, 5); +		REQUIRE(2 == handle2); +		REQUIRE(4 == lm.MarkValue(0)); +		lm.DeleteMarkFromHandle(handle2); +		REQUIRE(0 == lm.MarkValue(0)); +	} + +	SECTION("MarkerNext") { +		lm.AddMark(1, 1, 5); +		lm.AddMark(2, 2, 5); +		const Sci::Line line1 = lm.MarkerNext(0, 6); +		REQUIRE(1 == line1); +		const Sci::Line line2 = lm.MarkerNext(line1+1, 6); +		REQUIRE(2 == line2); +		const Sci::Line line3 = lm.MarkerNext(line2+1, 6); +		REQUIRE(-1 == line3); +	} + +	SECTION("MergeMarkers") { +		lm.AddMark(1, 1, 5); +		lm.AddMark(2, 2, 5); +		lm.MergeMarkers(1); +		REQUIRE(6 == lm.MarkValue(1)); +		REQUIRE(0 == lm.MarkValue(2)); +	} + +	SECTION("InsertRemoveLine") { +		const int handle1 = lm.AddMark(1, 1, 5); +		const int handle2 = lm.AddMark(2, 2, 5); +		lm.InsertLine(2); +		REQUIRE(0 == lm.MarkValue(0)); +		REQUIRE(2 == lm.MarkValue(1)); +		REQUIRE(0 == lm.MarkValue(2)); +		REQUIRE(4 == lm.MarkValue(3)); +		REQUIRE(0 == lm.MarkValue(4)); +		lm.RemoveLine(2); +		REQUIRE(0 == lm.MarkValue(0)); +		REQUIRE(2 == lm.MarkValue(1)); +		REQUIRE(4 == lm.MarkValue(2)); +		REQUIRE(0 == lm.MarkValue(3)); +		lm.InsertLines(2, 2); +		REQUIRE(0 == lm.MarkValue(0)); +		REQUIRE(2 == lm.MarkValue(1)); +		REQUIRE(0 == lm.MarkValue(2)); +		REQUIRE(0 == lm.MarkValue(3)); +		REQUIRE(4 == lm.MarkValue(4)); +		REQUIRE(0 == lm.MarkValue(5)); +		REQUIRE(1 == lm.LineFromHandle(handle1)); +		REQUIRE(4 == lm.LineFromHandle(handle2)); +	} +} + +TEST_CASE("LineLevels") { + +	LineLevels ll; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0)); +	} + +	SECTION("SetLevel") { +		REQUIRE(SC_FOLDLEVELBASE == ll.SetLevel(1, 200, 5)); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0)); +		REQUIRE(200 == ll.GetLevel(1)); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(2)); +		ll.ClearLevels(); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(1)); +		ll.ExpandLevels(5); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(7)); +	} + +	SECTION("InsertRemoveLine") { +		ll.SetLevel(1, 1, 5); +		ll.SetLevel(2, 2, 5); +		ll.InsertLine(2); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0)); +		REQUIRE(1 == ll.GetLevel(1)); +		REQUIRE(2 == ll.GetLevel(2)); +		REQUIRE(2 == ll.GetLevel(3)); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(4)); +		ll.RemoveLine(2); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0)); +		REQUIRE(1 == ll.GetLevel(1)); +		REQUIRE(2 == ll.GetLevel(2)); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(3)); +		ll.InsertLines(2, 2); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0)); +		REQUIRE(1 == ll.GetLevel(1)); +		REQUIRE(2 == ll.GetLevel(2)); +		REQUIRE(2 == ll.GetLevel(3)); +		REQUIRE(2 == ll.GetLevel(4)); +		REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(5)); +	} +} + +TEST_CASE("LineState") { + +	LineState ls; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(0 == ls.GetMaxLineState()); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(1 == ls.GetMaxLineState()); +		ls.Init(); +		REQUIRE(0 == ls.GetMaxLineState()); +		REQUIRE(0 == ls.GetLineState(0)); +	} + +	SECTION("SetLineState") { +		REQUIRE(0 == ls.SetLineState(1, 200)); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(200 == ls.GetLineState(1)); +		REQUIRE(0 == ls.GetLineState(2)); +		REQUIRE(0 == ls.SetLineState(2, 400)); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(200 == ls.GetLineState(1)); +		REQUIRE(400 == ls.GetLineState(2)); +		REQUIRE(0 == ls.GetLineState(3)); +		// GetLineState(3) expands to 4 lines +		REQUIRE(4 == ls.GetMaxLineState()); +		ls.Init(); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(1 == ls.GetMaxLineState()); +	} + +	SECTION("InsertRemoveLine") { +		REQUIRE(0 == ls.GetMaxLineState()); +		ls.SetLineState(1, 1); +		ls.SetLineState(2, 2); +		REQUIRE(3 == ls.GetMaxLineState()); +		ls.InsertLine(2); +		REQUIRE(4 == ls.GetMaxLineState()); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(1 == ls.GetLineState(1)); +		REQUIRE(2 == ls.GetLineState(2)); +		REQUIRE(2 == ls.GetLineState(3)); +		REQUIRE(0 == ls.GetLineState(4)); +		REQUIRE(5 == ls.GetMaxLineState()); +		ls.RemoveLine(2); +		REQUIRE(4 == ls.GetMaxLineState()); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(1 == ls.GetLineState(1)); +		REQUIRE(2 == ls.GetLineState(2)); +		REQUIRE(0 == ls.GetLineState(3)); +		ls.InsertLines(2, 2); +		REQUIRE(6 == ls.GetMaxLineState()); +		REQUIRE(0 == ls.GetLineState(0)); +		REQUIRE(1 == ls.GetLineState(1)); +		REQUIRE(2 == ls.GetLineState(2)); +		REQUIRE(2 == ls.GetLineState(3)); +		REQUIRE(2 == ls.GetLineState(4)); +		REQUIRE(0 == ls.GetLineState(5)); +	} +} + +TEST_CASE("LineAnnotation") { + +	LineAnnotation la; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(0 == la.Length(0)); +		REQUIRE(0 == la.Lines(0)); +		REQUIRE(0 == la.Style(0)); +		REQUIRE(false == la.MultipleStyles(0)); +	} + +	SECTION("SetText") { +		la.SetText(0, "Text"); +		REQUIRE(4 == la.Length(0)); +		REQUIRE(1 == la.Lines(0)); +		REQUIRE(memcmp(la.Text(0), "Text", 4) == 0); +		REQUIRE(nullptr == la.Styles(0)); +		REQUIRE(0 == la.Style(0)); +		la.SetStyle(0, 9); +		REQUIRE(9 == la.Style(0)); + +		la.SetText(0, "Ant\nBird\nCat"); +		REQUIRE(3 == la.Lines(0)); + +		la.ClearAll(); +		REQUIRE(nullptr == la.Text(0)); +	} + +	SECTION("SetStyles") { +		la.SetText(0, "Text"); +		const unsigned char styles[] { 1,2,3,4 }; +		la.SetStyles(0, styles); +		REQUIRE(memcmp(la.Text(0), "Text", 4) == 0); +		REQUIRE(memcmp(la.Styles(0), styles, 4) == 0); +		REQUIRE(la.MultipleStyles(0)); +	} + +	SECTION("InsertRemoveLine") { +		la.SetText(0, "Ant"); +		la.SetText(1, "Bird"); +		REQUIRE(3 == la.Length(0)); +		REQUIRE(4 == la.Length(1)); +		REQUIRE(1 == la.Lines(0)); +		la.InsertLine(1); +		REQUIRE(3 == la.Length(0)); +		REQUIRE(0 == la.Length(1)); +		REQUIRE(4 == la.Length(2)); +		la.RemoveLine(2); +		REQUIRE(3 == la.Length(0)); +		REQUIRE(4 == la.Length(1)); +		la.InsertLines(1, 2); +		REQUIRE(3 == la.Length(0)); +		REQUIRE(0 == la.Length(1)); +		REQUIRE(0 == la.Length(2)); +		REQUIRE(4 == la.Length(3)); +	} +} + +TEST_CASE("LineTabstops") { + +	LineTabstops lt; + +	SECTION("Initial") { +		// Initial State +		REQUIRE(0 == lt.GetNextTabstop(0, 0)); +	} + +	SECTION("AddClearTabstops") { +		lt.AddTabstop(0, 100); +		REQUIRE(100 == lt.GetNextTabstop(0, 0)); +		REQUIRE(0 == lt.GetNextTabstop(0, 100)); +		lt.ClearTabstops(0); +		REQUIRE(0 == lt.GetNextTabstop(0, 0)); +	} + +	SECTION("InsertRemoveLine") { +		lt.AddTabstop(0, 100); +		lt.AddTabstop(1, 200); +		lt.InsertLine(1); +		REQUIRE(100 == lt.GetNextTabstop(0, 0)); +		REQUIRE(0 == lt.GetNextTabstop(1, 0)); +		REQUIRE(200 == lt.GetNextTabstop(2, 0)); +		lt.RemoveLine(1); +		REQUIRE(100 == lt.GetNextTabstop(0, 0)); +		REQUIRE(200 == lt.GetNextTabstop(1, 0)); +		lt.InsertLines(1, 2); +		REQUIRE(100 == lt.GetNextTabstop(0, 0)); +		REQUIRE(0 == lt.GetNextTabstop(1, 0)); +		REQUIRE(0 == lt.GetNextTabstop(2, 0)); +		REQUIRE(200 == lt.GetNextTabstop(3, 0)); +		lt.Init(); +		REQUIRE(0 == lt.GetNextTabstop(0, 0)); +	} +} | 
