diff options
author | Neil <nyamatongwe@gmail.com> | 2025-01-31 12:36:49 +1100 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2025-01-31 12:36:49 +1100 |
commit | 6017737861df5f3799ec2538e5fb62fe378a309e (patch) | |
tree | 5ac8c50182793e2b2a79e9feeecf28bbed0856b6 | |
parent | e2d7f790b130234829cde227a1439812fb510e50 (diff) | |
download | scintilla-mirror-6017737861df5f3799ec2538e5fb62fe378a309e.tar.gz |
Add default basic constructor and operator!= to SelectionPosition to ease use.
Use default member initializer, constexpr for constructors and equality
operators and <, [[nodiscard]] for comparison operators.
Add simple unit tests for Selection. Not trying to be exhaustive here, just
start the process of adding tests.
-rw-r--r-- | src/Selection.cxx | 7 | ||||
-rw-r--r-- | src/Selection.h | 44 | ||||
-rw-r--r-- | test/unit/UnitTester.vcxproj | 1 | ||||
-rw-r--r-- | test/unit/makefile | 1 | ||||
-rw-r--r-- | test/unit/test.mak | 1 | ||||
-rw-r--r-- | test/unit/testSelection.cxx | 151 |
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()); + } + +} |