aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Selection.cxx7
-rw-r--r--src/Selection.h44
-rw-r--r--test/unit/UnitTester.vcxproj1
-rw-r--r--test/unit/makefile1
-rw-r--r--test/unit/test.mak1
-rw-r--r--test/unit/testSelection.cxx151
6 files changed, 179 insertions, 26 deletions
diff --git a/src/Selection.cxx b/src/Selection.cxx
index 5b99b7c3a..ad63afd70 100644
--- a/src/Selection.cxx
+++ b/src/Selection.cxx
@@ -52,13 +52,6 @@ void SelectionPosition::MoveForInsertDelete(bool insertion, Sci::Position startC
}
}
-bool SelectionPosition::operator <(const SelectionPosition &other) const noexcept {
- if (position == other.position)
- return virtualSpace < other.virtualSpace;
- else
- return position < other.position;
-}
-
bool SelectionPosition::operator >(const SelectionPosition &other) const noexcept {
if (position == other.position)
return virtualSpace > other.virtualSpace;
diff --git a/src/Selection.h b/src/Selection.h
index c0d785870..7f3fd937b 100644
--- a/src/Selection.h
+++ b/src/Selection.h
@@ -11,10 +11,11 @@
namespace Scintilla::Internal {
class SelectionPosition {
- Sci::Position position;
- Sci::Position virtualSpace;
+ Sci::Position position = Sci::invalidPosition;
+ Sci::Position virtualSpace = 0;
public:
- explicit SelectionPosition(Sci::Position position_= Sci::invalidPosition, Sci::Position virtualSpace_=0) noexcept : position(position_), virtualSpace(virtualSpace_) {
+ constexpr SelectionPosition() noexcept = default;
+ constexpr explicit SelectionPosition(Sci::Position position_, Sci::Position virtualSpace_=0) noexcept : position(position_), virtualSpace(virtualSpace_) {
PLATFORM_ASSERT(virtualSpace < 800000000);
if (virtualSpace < 0)
virtualSpace = 0;
@@ -24,13 +25,20 @@ public:
virtualSpace = 0;
}
void MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length, bool moveForEqual) noexcept;
- bool operator ==(const SelectionPosition &other) const noexcept {
- return position == other.position && virtualSpace == other.virtualSpace;
+ [[nodiscard]] constexpr bool operator ==(const SelectionPosition &other) const noexcept {
+ return (position == other.position) && (virtualSpace == other.virtualSpace);
}
- bool operator <(const SelectionPosition &other) const noexcept;
- bool operator >(const SelectionPosition &other) const noexcept;
- bool operator <=(const SelectionPosition &other) const noexcept;
- bool operator >=(const SelectionPosition &other) const noexcept;
+ [[nodiscard]] constexpr bool operator !=(const SelectionPosition &other) const noexcept {
+ return (position != other.position) || (virtualSpace != other.virtualSpace);
+ }
+ [[nodiscard]] constexpr bool operator <(const SelectionPosition &other) const noexcept {
+ if (position == other.position)
+ return virtualSpace < other.virtualSpace;
+ return position < other.position;
+ }
+ [[nodiscard]] bool operator >(const SelectionPosition &other) const noexcept;
+ [[nodiscard]] bool operator <=(const SelectionPosition &other) const noexcept;
+ [[nodiscard]] bool operator >=(const SelectionPosition &other) const noexcept;
Sci::Position Position() const noexcept {
return position;
}
@@ -61,9 +69,8 @@ public:
struct SelectionSegment {
SelectionPosition start;
SelectionPosition end;
- SelectionSegment() noexcept : start(), end() {
- }
- SelectionSegment(SelectionPosition a, SelectionPosition b) noexcept {
+ constexpr SelectionSegment() noexcept = default;
+ constexpr SelectionSegment(SelectionPosition a, SelectionPosition b) noexcept {
if (a < b) {
start = a;
end = b;
@@ -96,15 +103,14 @@ struct SelectionRange {
SelectionPosition caret;
SelectionPosition anchor;
- SelectionRange() noexcept : caret(), anchor() {
- }
- explicit SelectionRange(SelectionPosition single) noexcept : caret(single), anchor(single) {
+ constexpr SelectionRange() noexcept = default;
+ constexpr explicit SelectionRange(SelectionPosition single) noexcept : caret(single), anchor(single) {
}
- explicit SelectionRange(Sci::Position single) noexcept : caret(single), anchor(single) {
+ constexpr explicit SelectionRange(Sci::Position single) noexcept : caret(single), anchor(single) {
}
- SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) noexcept : caret(caret_), anchor(anchor_) {
+ constexpr SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) noexcept : caret(caret_), anchor(anchor_) {
}
- SelectionRange(Sci::Position caret_, Sci::Position anchor_) noexcept : caret(caret_), anchor(anchor_) {
+ constexpr SelectionRange(Sci::Position caret_, Sci::Position anchor_) noexcept : caret(caret_), anchor(anchor_) {
}
bool Empty() const noexcept {
return anchor == caret;
@@ -158,7 +164,7 @@ public:
enum class SelTypes { none, stream, rectangle, lines, thin };
SelTypes selType;
- Selection();
+ Selection(); // Allocates so may throw.
bool IsRectangular() const noexcept;
Sci::Position MainCaret() const noexcept;
Sci::Position MainAnchor() const noexcept;
diff --git a/test/unit/UnitTester.vcxproj b/test/unit/UnitTester.vcxproj
index fdf567cff..87688523b 100644
--- a/test/unit/UnitTester.vcxproj
+++ b/test/unit/UnitTester.vcxproj
@@ -165,6 +165,7 @@
<ClCompile Include="..\..\src\PerLine.cxx" />
<ClCompile Include="..\..\src\RESearch.cxx" />
<ClCompile Include="..\..\src\RunStyles.cxx" />
+ <ClCompile Include="..\..\src\Selection.cxx" />
<ClCompile Include="..\..\src\UndoHistory.cxx" />
<ClCompile Include="..\..\src\UniConversion.cxx" />
<ClCompile Include="..\..\src\UniqueString.cxx" />
diff --git a/test/unit/makefile b/test/unit/makefile
index 866727505..695551fc9 100644
--- a/test/unit/makefile
+++ b/test/unit/makefile
@@ -68,6 +68,7 @@ Geometry.o \
PerLine.o \
RESearch.o \
RunStyles.o \
+Selection.o \
UndoHistory.o \
UniConversion.o \
UniqueString.o
diff --git a/test/unit/test.mak b/test/unit/test.mak
index e4a448f8c..15d9eba43 100644
--- a/test/unit/test.mak
+++ b/test/unit/test.mak
@@ -25,6 +25,7 @@ TESTEDSRC=\
../../src/PerLine.cxx \
../../src/RESearch.cxx \
../../src/RunStyles.cxx \
+ ../../src/Selection.cxx \
../../src/UndoHistory.cxx \
../../src/UniConversion.cxx \
../../src/UniqueString.cxx
diff --git a/test/unit/testSelection.cxx b/test/unit/testSelection.cxx
new file mode 100644
index 000000000..8c27b42e8
--- /dev/null
+++ b/test/unit/testSelection.cxx
@@ -0,0 +1,151 @@
+/** @file testSelection.cxx
+ ** Unit Tests for Scintilla internal data structures
+ **/
+
+#include <cstdint>
+
+#include <stdexcept>
+#include <string_view>
+#include <vector>
+
+#include "Debugging.h"
+
+#include "Position.h"
+#include "Selection.h"
+
+#include "catch.hpp"
+
+using namespace Scintilla;
+using namespace Scintilla::Internal;
+
+// Test Selection.
+
+namespace {
+
+constexpr SelectionPosition invalid;
+constexpr SelectionPosition zero(0);
+constexpr SelectionRange rangeInvalid;
+constexpr SelectionRange rangeZero(0);
+
+}
+
+TEST_CASE("SelectionPosition") {
+
+ SECTION("SelectionPosition") {
+ SelectionPosition sel;
+ REQUIRE(sel.Position() == Sci::invalidPosition);
+ REQUIRE(sel.VirtualSpace() == 0);
+ REQUIRE(!sel.IsValid());
+ REQUIRE(sel.VirtualSpace() == 0);
+
+ REQUIRE(sel == invalid);
+ REQUIRE(sel != zero);
+ sel.Reset();
+ REQUIRE(sel != invalid);
+ REQUIRE(sel == zero);
+ }
+
+ SECTION("Comparison") {
+ constexpr SelectionPosition sel(2,3);
+ REQUIRE(sel > invalid);
+ REQUIRE(sel > zero);
+ REQUIRE(sel >= zero);
+ REQUIRE(zero < sel);
+ REQUIRE(zero <= sel);
+
+ SelectionPosition virtuous(0, 4);
+ REQUIRE(virtuous > zero);
+ REQUIRE(virtuous >= zero);
+ REQUIRE(zero < virtuous);
+ REQUIRE(zero <= virtuous);
+
+ REQUIRE(virtuous.Position() == 0);
+ REQUIRE(virtuous.VirtualSpace() == 4);
+
+ virtuous.SetPosition(1); // Also resets virtualSpace
+ REQUIRE(virtuous.Position() == 1);
+ REQUIRE(virtuous.VirtualSpace() == 0);
+ virtuous.SetVirtualSpace(3); // Does not reset position
+ REQUIRE(virtuous.Position() == 1);
+ REQUIRE(virtuous.VirtualSpace() == 3);
+ }
+
+ SECTION("Add") {
+ SelectionPosition sel(2,3);
+ sel.Add(1);
+ REQUIRE(sel.Position() == 3);
+ REQUIRE(sel.VirtualSpace() == 3);
+ sel.AddVirtualSpace(2);
+ REQUIRE(sel.Position() == 3);
+ REQUIRE(sel.VirtualSpace() == 5);
+ }
+
+ SECTION("MoveForInsertDelete") {
+ // There are multiple details implemented in MoveForInsertDelete that are supposed to
+ // move selections in a way that appears to be natural to a user.
+
+ SelectionPosition sel(2,3);
+ sel.MoveForInsertDelete(true, 0,1, false);
+ REQUIRE(sel == SelectionPosition(3,3));
+
+ // Converts a virtual space to real space
+ sel.MoveForInsertDelete(true, 3,1, false);
+ REQUIRE(sel == SelectionPosition(4,2));
+
+ // Deletion at position clears virtual space
+ sel.MoveForInsertDelete(false, 4,1, false);
+ REQUIRE(sel == SelectionPosition(4,0));
+
+ sel.MoveForInsertDelete(false, 3,1, false);
+ REQUIRE(sel == SelectionPosition(3,0));
+
+ // Insert at position with and without move for equal
+ sel.MoveForInsertDelete(true, 3, 1, false);
+ REQUIRE(sel == SelectionPosition(3, 0));
+ sel.MoveForInsertDelete(true, 3, 1, true);
+ REQUIRE(sel == SelectionPosition(4, 0));
+
+ // Deletion over the position moves to start of deletion
+ sel.MoveForInsertDelete(false, 2, 5, false);
+ REQUIRE(sel == SelectionPosition(2, 0));
+ }
+
+}
+
+TEST_CASE("SelectionSegment") {
+
+ SECTION("SelectionSegment") {
+ SelectionSegment ss;
+ REQUIRE(ss.start == invalid);
+ REQUIRE(ss.end == invalid);
+ }
+
+}
+
+TEST_CASE("SelectionRange") {
+
+ SECTION("SelectionRange") {
+ SelectionRange sr;
+ REQUIRE(sr.anchor == invalid);
+ REQUIRE(sr.caret == invalid);
+ }
+
+}
+
+TEST_CASE("Selection") {
+
+ SECTION("Selection") {
+ Selection sel;
+
+ REQUIRE(sel.selType == Selection::SelTypes::stream);
+ REQUIRE(!sel.IsRectangular());
+ REQUIRE(sel.Count() == 1);
+ REQUIRE(sel.Main() == 0);
+
+ REQUIRE(sel.Range(0) == rangeZero);
+ REQUIRE(sel.RangeMain() == rangeZero);
+ REQUIRE(sel.Rectangular() == rangeInvalid);
+ REQUIRE(sel.Empty());
+ }
+
+}