aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--test/unit/README14
-rw-r--r--test/unit/SciTE.properties4
-rw-r--r--test/unit/makefile62
-rw-r--r--test/unit/testContractionState.cxx125
-rw-r--r--test/unit/testPartitioning.cxx208
-rw-r--r--test/unit/testRunStyles.cxx167
-rw-r--r--test/unit/testSplitVector.cxx220
-rw-r--r--test/unit/unitTest.cxx50
8 files changed, 850 insertions, 0 deletions
diff --git a/test/unit/README b/test/unit/README
new file mode 100644
index 000000000..0d70fe71f
--- /dev/null
+++ b/test/unit/README
@@ -0,0 +1,14 @@
+The test/unit directory contains unit tests for Scintilla data structures.
+
+The tests can be run on Windows or Linux using g++ and GNU make.
+The Google Test framework is used.
+http://code.google.com/p/googletest/
+
+Google test must be installed first.
+On Linux, install the google test packages libgtest-dev and libgtest0.
+On Windows download Google test and install it as a peer to the directory
+containing scintilla. The makefile assumes it is in ../../../../gtest-1.5.0.
+
+To run the tests:
+make
+./unitTest
diff --git a/test/unit/SciTE.properties b/test/unit/SciTE.properties
new file mode 100644
index 000000000..8cc762e96
--- /dev/null
+++ b/test/unit/SciTE.properties
@@ -0,0 +1,4 @@
+if PLAT_WIN
+ make.command=mingw32-make
+command.go.*.cxx=./unitTest
+command.go.needs.$(file.patterns.cplusplus)=$(make.command)
diff --git a/test/unit/makefile b/test/unit/makefile
new file mode 100644
index 000000000..6a4ec8747
--- /dev/null
+++ b/test/unit/makefile
@@ -0,0 +1,62 @@
+# Build all the unit tests
+# Should be run using mingw32-make on Windows
+
+.SUFFIXES: .cxx
+
+GTEST_DIR = ../../../../gtest-1.5.0
+
+ifdef windir
+
+DEL = del /q
+# Find Google Test headers.
+CPPFLAGS += -I$(GTEST_DIR)/include
+GTEST_ALL = gtest-all.o
+LINKFLAGS = $(CPPFLAGS) $(CXXFLAGS)
+
+else
+
+DEL = rm -f
+CPPFLAGS = $(shell gtest-config --cppflags)
+CXXFLAGS = $(shell gtest-config --cxxflags)
+LINKFLAGS = $(shell gtest-config --ldflags --libs)
+
+endif
+
+#vpath %.cxx ../src ../lexlib ../lexers
+vpath %.cxx ../../src
+
+
+INCLUDEDIRS = -I ../../include -I ../../src -I../../lexlib
+
+
+# Find headers of test code.
+CPPFLAGS += $(INCLUDEDIRS)
+
+CXXFLAGS += -g -Wall -Wextra -Wno-unused-function
+#~ CXXFLAGS += -g -Wall
+
+CASES:=$(addsuffix .o,$(basename $(notdir $(wildcard test*.cxx))))
+TESTEDOBJS=ContractionState.o RunStyles.o
+
+TESTS=unitTest
+
+GTEST_HEADERS=$(GTEST_DIR)/include/gtest/*.h $(GTEST_DIR)/include/gtest/internal/*.h
+
+all: $(TESTS)
+
+clean:
+ $(DEL) $(TESTS) *.a *.o *.exe
+
+# Usually you shouldn't tweak such internal variables, indicated by a
+# trailing _.
+GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
+
+gtest-all.o: $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(GTEST_DIR) -c \
+ $(GTEST_DIR)/src/gtest-all.cc
+
+.cxx.o:
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+unitTest: $(CASES) $(TESTEDOBJS) unitTest.o $(GTEST_ALL)
+ $(CXX) $(LINKFLAGS) $^ -o $@
diff --git a/test/unit/testContractionState.cxx b/test/unit/testContractionState.cxx
new file mode 100644
index 000000000..96a7bbf8a
--- /dev/null
+++ b/test/unit/testContractionState.cxx
@@ -0,0 +1,125 @@
+// Unit Tests for Scintilla internal data structures
+
+#include <string.h>
+
+#include "Platform.h"
+
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+
+#include <gtest/gtest.h>
+
+// Test ContractionState.
+
+class ContractionStateTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ pcs = new ContractionState();
+ }
+
+ virtual void TearDown() {
+ delete pcs;
+ pcs = 0;
+ }
+
+ ContractionState *pcs;
+};
+
+TEST_F(ContractionStateTest, IsEmptyInitially) {
+ EXPECT_EQ(1, pcs->LinesInDoc());
+ EXPECT_EQ(1, pcs->LinesDisplayed());
+ EXPECT_EQ(0, pcs->DisplayFromDoc(0));
+ EXPECT_EQ(0, pcs->DocFromDisplay(0));
+}
+
+TEST_F(ContractionStateTest, OneLine) {
+ pcs->InsertLine(0);
+ EXPECT_EQ(2, pcs->LinesInDoc());
+ EXPECT_EQ(2, pcs->LinesDisplayed());
+ EXPECT_EQ(0, pcs->DisplayFromDoc(0));
+ EXPECT_EQ(0, pcs->DocFromDisplay(0));
+ EXPECT_EQ(1, pcs->DisplayFromDoc(1));
+ EXPECT_EQ(1, pcs->DocFromDisplay(1));
+}
+
+TEST_F(ContractionStateTest, InsertionThenDeletions) {
+ pcs->InsertLines(0,4);
+ pcs->DeleteLine(1);
+
+ EXPECT_EQ(4, pcs->LinesInDoc());
+ EXPECT_EQ(4, pcs->LinesDisplayed());
+ for (int l=0;l<4;l++) {
+ EXPECT_EQ(l, pcs->DisplayFromDoc(l));
+ EXPECT_EQ(l, pcs->DocFromDisplay(l));
+ }
+
+ pcs->DeleteLines(0,2);
+ EXPECT_EQ(2, pcs->LinesInDoc());
+ EXPECT_EQ(2, pcs->LinesDisplayed());
+ for (int l=0;l<2;l++) {
+ EXPECT_EQ(l, pcs->DisplayFromDoc(l));
+ EXPECT_EQ(l, pcs->DocFromDisplay(l));
+ }
+}
+
+TEST_F(ContractionStateTest, ShowHide) {
+ pcs->InsertLines(0,4);
+ EXPECT_EQ(true, pcs->GetVisible(0));
+ EXPECT_EQ(true, pcs->GetVisible(1));
+ EXPECT_EQ(true, pcs->GetVisible(2));
+ EXPECT_EQ(5, pcs->LinesDisplayed());
+
+ pcs->SetVisible(1, 1, false);
+ EXPECT_EQ(true, pcs->GetVisible(0));
+ EXPECT_EQ(0, pcs->GetVisible(1));
+ EXPECT_EQ(true, pcs->GetVisible(2));
+ EXPECT_EQ(4, pcs->LinesDisplayed());
+
+ pcs->SetVisible(1, 2, true);
+ for (int l=0;l<4;l++) {
+ EXPECT_EQ(true, pcs->GetVisible(0));
+ }
+
+ pcs->SetVisible(1, 1, false);
+ EXPECT_EQ(0, pcs->GetVisible(1));
+ pcs->ShowAll();
+ for (int l=0;l<4;l++) {
+ EXPECT_EQ(true, pcs->GetVisible(0));
+ }
+}
+
+TEST_F(ContractionStateTest, Contracting) {
+ pcs->InsertLines(0,4);
+ for (int l=0;l<4;l++) {
+ EXPECT_EQ(true, pcs->GetExpanded(l));
+ }
+
+ pcs->SetExpanded(2, false);
+ EXPECT_EQ(true, pcs->GetExpanded(1));
+ EXPECT_EQ(0, pcs->GetExpanded(2));
+ EXPECT_EQ(true, pcs->GetExpanded(3));
+
+ EXPECT_EQ(2, pcs->ContractedNext(0));
+ EXPECT_EQ(2, pcs->ContractedNext(1));
+ EXPECT_EQ(2, pcs->ContractedNext(2));
+ EXPECT_EQ(-1, pcs->ContractedNext(3));
+
+ pcs->SetExpanded(2, true);
+ EXPECT_EQ(true, pcs->GetExpanded(1));
+ EXPECT_EQ(true, pcs->GetExpanded(2));
+ EXPECT_EQ(true, pcs->GetExpanded(3));
+}
+
+TEST_F(ContractionStateTest, ChangeHeight) {
+ pcs->InsertLines(0,4);
+ for (int l=0;l<4;l++) {
+ EXPECT_EQ(1, pcs->GetHeight(l));
+ }
+
+ pcs->SetHeight(1, 2);
+ EXPECT_EQ(1, pcs->GetHeight(0));
+ EXPECT_EQ(2, pcs->GetHeight(1));
+ EXPECT_EQ(1, pcs->GetHeight(2));
+}
diff --git a/test/unit/testPartitioning.cxx b/test/unit/testPartitioning.cxx
new file mode 100644
index 000000000..7eff5d9c9
--- /dev/null
+++ b/test/unit/testPartitioning.cxx
@@ -0,0 +1,208 @@
+// Unit Tests for Scintilla internal data structures
+
+#include <string.h>
+
+#include "Platform.h"
+
+#include "SplitVector.h"
+#include "Partitioning.h"
+
+#include <gtest/gtest.h>
+
+const int growSize = 4;
+
+const int lengthTestArray = 8;
+static const int testArray[lengthTestArray] = {3, 4, 5, 6, 7, 8, 9, 10};
+
+// Test SplitVectorWithRangeAdd.
+
+class SplitVectorWithRangeAddTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ psvwra = new SplitVectorWithRangeAdd(growSize);
+ }
+
+ virtual void TearDown() {
+ delete psvwra;
+ psvwra = 0;
+ }
+
+ SplitVectorWithRangeAdd *psvwra;
+};
+
+TEST_F(SplitVectorWithRangeAddTest, IsEmptyInitially) {
+ EXPECT_EQ(0, psvwra->Length());
+}
+
+TEST_F(SplitVectorWithRangeAddTest, IncrementExceptEnds) {
+ psvwra->InsertFromArray(0, testArray, 0, lengthTestArray);
+ psvwra->RangeAddDelta(1, lengthTestArray-1, 1);
+ for (int i=0; i<psvwra->Length(); i++) {
+ if ((i == 0) || (i == lengthTestArray-1))
+ EXPECT_EQ(i+3, psvwra->ValueAt(i));
+ else
+ EXPECT_EQ(i+4, psvwra->ValueAt(i));
+ }
+}
+
+// Test Partitioning.
+
+class PartitioningTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ pp = new Partitioning(growSize);
+ }
+
+ virtual void TearDown() {
+ delete pp;
+ pp = 0;
+ }
+
+ Partitioning *pp;
+};
+
+TEST_F(PartitioningTest, IsEmptyInitially) {
+ EXPECT_EQ(1, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(pp->Partitions()));
+ EXPECT_EQ(0, pp->PartitionFromPosition(0));
+}
+
+TEST_F(PartitioningTest, SimpleInsert) {
+ pp->InsertText(0, 1);
+ EXPECT_EQ(1, pp->Partitions());
+ EXPECT_EQ(1, pp->PositionFromPartition(pp->Partitions()));
+}
+
+TEST_F(PartitioningTest, TwoPartitions) {
+ pp->InsertText(0, 2);
+ pp->InsertPartition(1, 1);
+ EXPECT_EQ(2, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(1, pp->PositionFromPartition(1));
+ EXPECT_EQ(2, pp->PositionFromPartition(2));
+}
+
+TEST_F(PartitioningTest, MoveStart) {
+ pp->InsertText(0, 3);
+ pp->InsertPartition(1, 2);
+ pp->SetPartitionStartPosition(1,1);
+ EXPECT_EQ(2, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(1, pp->PositionFromPartition(1));
+ EXPECT_EQ(3, pp->PositionFromPartition(2));
+}
+
+TEST_F(PartitioningTest, InsertAgain) {
+ pp->InsertText(0, 3);
+ pp->InsertPartition(1, 2);
+ pp->InsertText(0,3);
+ pp->InsertText(1,2);
+ EXPECT_EQ(2, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(5, pp->PositionFromPartition(1));
+ EXPECT_EQ(8, pp->PositionFromPartition(2));
+}
+
+TEST_F(PartitioningTest, InsertReversed) {
+ pp->InsertText(0, 3);
+ pp->InsertPartition(1, 2);
+ pp->InsertText(1,2);
+ pp->InsertText(0,3);
+ EXPECT_EQ(2, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(5, pp->PositionFromPartition(1));
+ EXPECT_EQ(8, pp->PositionFromPartition(2));
+}
+
+TEST_F(PartitioningTest, InverseSearch) {
+ pp->InsertText(0, 3);
+ pp->InsertPartition(1, 2);
+ pp->SetPartitionStartPosition(1,1);
+
+ EXPECT_EQ(2, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(1, pp->PositionFromPartition(1));
+ EXPECT_EQ(3, pp->PositionFromPartition(2));
+
+ EXPECT_EQ(0, pp->PartitionFromPosition(0));
+ EXPECT_EQ(1, pp->PartitionFromPosition(1));
+ EXPECT_EQ(1, pp->PartitionFromPosition(2));
+
+ EXPECT_EQ(1, pp->PartitionFromPosition(3));
+}
+
+TEST_F(PartitioningTest, DeletePartition) {
+ pp->InsertText(0, 2);
+ pp->InsertPartition(1, 1);
+ pp->RemovePartition(1);
+ EXPECT_EQ(1, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(2, pp->PositionFromPartition(1));
+}
+
+TEST_F(PartitioningTest, DeleteAll) {
+ pp->InsertText(0, 3);
+ pp->InsertPartition(1, 2);
+ pp->SetPartitionStartPosition(1,1);
+ pp->DeleteAll();
+ // Back to initial state
+ EXPECT_EQ(1, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(pp->Partitions()));
+}
+
+TEST_F(PartitioningTest, TestBackwards) {
+ pp->InsertText(0, 10);
+ pp->InsertPartition(1, 3);
+ pp->InsertPartition(2, 6);
+ pp->InsertPartition(3, 9);
+ pp->InsertText(2,4);
+ pp->InsertText(1,2);
+ pp->InsertText(0,3);
+ EXPECT_EQ(4, pp->Partitions());
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(6, pp->PositionFromPartition(1));
+ EXPECT_EQ(11, pp->PositionFromPartition(2));
+ EXPECT_EQ(18, pp->PositionFromPartition(3));
+ EXPECT_EQ(19, pp->PositionFromPartition(4));
+}
+
+TEST_F(PartitioningTest, TestMany) {
+ // Provoke backstep call
+ pp->InsertText(0, 42);
+ for (int i=0; i<20; i++) {
+ pp->InsertPartition(i+1, (i+1) * 2);
+ }
+ for (int i=20; i>0; i--) {
+ pp->InsertText(i,2);
+ }
+ EXPECT_EQ(21, pp->Partitions());
+ for (int i=1; i<20; i++) {
+ EXPECT_EQ(i*4 - 2, pp->PositionFromPartition(i));
+ EXPECT_EQ(i, pp->PartitionFromPosition(i*4 - 2));
+ }
+ pp->InsertText(19,2);
+ EXPECT_EQ(3, pp->PartitionFromPosition(10));
+ pp->InsertText(0,2);
+ pp->InsertText(0,-2);
+ pp->RemovePartition(1);
+ EXPECT_EQ(0, pp->PositionFromPartition(0));
+ EXPECT_EQ(6, pp->PositionFromPartition(1));
+ EXPECT_EQ(10, pp->PositionFromPartition(2));
+ pp->RemovePartition(10);
+ EXPECT_EQ(46, pp->PositionFromPartition(10));
+ EXPECT_EQ(10, pp->PartitionFromPosition(46));
+ EXPECT_EQ(50, pp->PositionFromPartition(11));
+ EXPECT_EQ(11, pp->PartitionFromPosition(50));
+}
+
+#if !PLAT_WIN
+// Omit death tests on Windows where they trigger a system "unitTest.exe has stopped working" popup.
+TEST_F(PartitioningTest, OutOfRangeDeathTest) {
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ pp->InsertText(0, 2);
+ pp->InsertPartition(1, 1);
+ EXPECT_EQ(2, pp->Partitions());
+ ASSERT_DEATH(pp->PositionFromPartition(-1), "Assertion");
+ ASSERT_DEATH(pp->PositionFromPartition(3), "Assertion");
+}
+#endif
diff --git a/test/unit/testRunStyles.cxx b/test/unit/testRunStyles.cxx
new file mode 100644
index 000000000..d5bf1bb08
--- /dev/null
+++ b/test/unit/testRunStyles.cxx
@@ -0,0 +1,167 @@
+// Unit Tests for Scintilla internal data structures
+
+#include <string.h>
+
+#include "Platform.h"
+
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+
+#include <gtest/gtest.h>
+
+// Test RunStyles.
+
+class RunStylesTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ prs = new RunStyles();
+ }
+
+ virtual void TearDown() {
+ delete prs;
+ prs = 0;
+ }
+
+ RunStyles *prs;
+};
+
+TEST_F(RunStylesTest, IsEmptyInitially) {
+ EXPECT_EQ(0, prs->Length());
+}
+
+TEST_F(RunStylesTest, SimpleInsert) {
+ prs->InsertSpace(0, 1);
+ EXPECT_EQ(1, prs->Length());
+ EXPECT_EQ(0, prs->ValueAt(0));
+ EXPECT_EQ(1, prs->FindNextChange(0, prs->Length()));
+ EXPECT_EQ(2, prs->FindNextChange(1, prs->Length()));
+}
+
+TEST_F(RunStylesTest, TwoRuns) {
+ prs->InsertSpace(0, 2);
+ EXPECT_EQ(2, prs->Length());
+ prs->SetValueAt(0, 2);
+ EXPECT_EQ(2, prs->ValueAt(0));
+ EXPECT_EQ(0, prs->ValueAt(1));
+ EXPECT_EQ(1, prs->FindNextChange(0, prs->Length()));
+ EXPECT_EQ(2, prs->FindNextChange(1, prs->Length()));
+ EXPECT_EQ(3, prs->FindNextChange(2, prs->Length()));
+}
+
+TEST_F(RunStylesTest, LongerRuns) {
+ prs->InsertSpace(0, 5);
+ prs->SetValueAt(0, 3);
+ prs->SetValueAt(1, 3);
+ EXPECT_EQ(3, prs->ValueAt(0));
+ EXPECT_EQ(3, prs->ValueAt(1));
+ EXPECT_EQ(0, prs->ValueAt(2));
+
+ EXPECT_EQ(0, prs->StartRun(0));
+ EXPECT_EQ(2, prs->EndRun(0));
+
+ EXPECT_EQ(0, prs->StartRun(1));
+ EXPECT_EQ(2, prs->EndRun(1));
+
+ EXPECT_EQ(2, prs->StartRun(2));
+ EXPECT_EQ(5, prs->EndRun(2));
+
+ EXPECT_EQ(2, prs->StartRun(3));
+ EXPECT_EQ(5, prs->EndRun(3));
+
+ EXPECT_EQ(2, prs->StartRun(4));
+ EXPECT_EQ(5, prs->EndRun(4));
+
+ // At end
+ EXPECT_EQ(2, prs->StartRun(5));
+ EXPECT_EQ(5, prs->EndRun(5));
+
+ // After end is same as end
+ EXPECT_EQ(2, prs->StartRun(6));
+ EXPECT_EQ(5, prs->EndRun(6));
+
+ EXPECT_EQ(2, prs->FindNextChange(0, prs->Length()));
+ EXPECT_EQ(5, prs->FindNextChange(2, prs->Length()));
+ EXPECT_EQ(6, prs->FindNextChange(5, prs->Length()));
+}
+
+TEST_F(RunStylesTest, FillRange) {
+ prs->InsertSpace(0, 5);
+ int startFill = 1;
+ int lengthFill = 3;
+ EXPECT_EQ(true, prs->FillRange(startFill, 99, lengthFill));
+ EXPECT_EQ(1, startFill);
+ EXPECT_EQ(3, lengthFill);
+
+ EXPECT_EQ(0, prs->ValueAt(0));
+ EXPECT_EQ(99, prs->ValueAt(1));
+ EXPECT_EQ(99, prs->ValueAt(2));
+ EXPECT_EQ(99, prs->ValueAt(3));
+ EXPECT_EQ(0, prs->ValueAt(4));
+
+ EXPECT_EQ(0, prs->StartRun(0));
+ EXPECT_EQ(1, prs->EndRun(0));
+
+ EXPECT_EQ(1, prs->StartRun(1));
+ EXPECT_EQ(4, prs->EndRun(1));
+}
+
+TEST_F(RunStylesTest, FillRangeAlreadyFilled) {
+ prs->InsertSpace(0, 5);
+ int startFill = 1;
+ int lengthFill = 3;
+ EXPECT_EQ(true, prs->FillRange(startFill, 99, lengthFill));
+ EXPECT_EQ(1, startFill);
+ EXPECT_EQ(3, lengthFill);
+
+ int startFill2 = 2;
+ int lengthFill2 = 1;
+ // Compiler warnings if 'false' used instead of '0' as expected value:
+ EXPECT_EQ(0, prs->FillRange(startFill2, 99, lengthFill2));
+ EXPECT_EQ(2, startFill2);
+ EXPECT_EQ(1, lengthFill2);
+}
+
+TEST_F(RunStylesTest, FillRangeAlreadyPartFilled) {
+ prs->InsertSpace(0, 5);
+ int startFill = 1;
+ int lengthFill = 2;
+ EXPECT_EQ(true, prs->FillRange(startFill, 99, lengthFill));
+ EXPECT_EQ(1, startFill);
+ EXPECT_EQ(2, lengthFill);
+
+ int startFill2 = 2;
+ int lengthFill2 = 2;
+ EXPECT_EQ(true, prs->FillRange(startFill2, 99, lengthFill2));
+ EXPECT_EQ(3, startFill2);
+ EXPECT_EQ(1, lengthFill2);
+}
+
+TEST_F(RunStylesTest, DeleteRange) {
+ prs->InsertSpace(0, 5);
+ prs->SetValueAt(0, 3);
+ prs->SetValueAt(1, 3);
+ prs->DeleteRange(1, 1);
+ EXPECT_EQ(4, prs->Length());
+ EXPECT_EQ(3, prs->ValueAt(0));
+ EXPECT_EQ(0, prs->ValueAt(1));
+
+ EXPECT_EQ(0, prs->StartRun(0));
+ EXPECT_EQ(1, prs->EndRun(0));
+
+ EXPECT_EQ(1, prs->StartRun(1));
+ EXPECT_EQ(4, prs->EndRun(1));
+
+ EXPECT_EQ(1, prs->StartRun(2));
+ EXPECT_EQ(4, prs->EndRun(2));
+}
+
+TEST_F(RunStylesTest, DeleteAll) {
+ prs->InsertSpace(0, 5);
+ prs->SetValueAt(0, 3);
+ prs->SetValueAt(1, 3);
+ prs->DeleteAll();
+ EXPECT_EQ(0, prs->Length());
+ EXPECT_EQ(0, prs->ValueAt(0));
+}
+
diff --git a/test/unit/testSplitVector.cxx b/test/unit/testSplitVector.cxx
new file mode 100644
index 000000000..b5d9a1d36
--- /dev/null
+++ b/test/unit/testSplitVector.cxx
@@ -0,0 +1,220 @@
+// Unit Tests for Scintilla internal data structures
+
+#include <string.h>
+
+#include "Platform.h"
+
+#include "SplitVector.h"
+
+#include <gtest/gtest.h>
+
+// Test SplitVector.
+
+class SplitVectorTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ psv = new SplitVector<int>;
+ }
+
+ virtual void TearDown() {
+ delete psv;
+ psv = 0;
+ }
+
+ SplitVector<int> *psv;
+};
+
+const int lengthTestArray = 4;
+static const int testArray[4] = {3, 4, 5, 6};
+
+TEST_F(SplitVectorTest, IsEmptyInitially) {
+ EXPECT_EQ(0, psv->Length());
+}
+
+TEST_F(SplitVectorTest, InsertOne) {
+ psv->InsertValue(0, 10, 0);
+ psv->Insert(5, 3);
+ EXPECT_EQ(11, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i == 5) ? 3 : 0, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, Insertion) {
+ psv->InsertValue(0, 10, 0);
+ EXPECT_EQ(10, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(0, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, EnsureLength) {
+ psv->EnsureLength(4);
+ EXPECT_EQ(4, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(0, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, InsertFromArray) {
+ psv->InsertFromArray(0, testArray, 0, lengthTestArray);
+ EXPECT_EQ(lengthTestArray, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(i+3, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, SetValue) {
+ psv->InsertValue(0, 10, 0);
+ psv->SetValueAt(5, 3);
+ EXPECT_EQ(10, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i == 5) ? 3 : 0, psv->ValueAt(i));
+ }
+ // Move the gap
+ psv->InsertValue(7, 1, 17);
+ EXPECT_EQ(17, psv->ValueAt(7));
+ EXPECT_EQ(0, psv->ValueAt(8));
+ // Set after the gap
+ psv->SetValueAt(8, 19);
+ EXPECT_EQ(19, psv->ValueAt(8));
+}
+
+TEST_F(SplitVectorTest, Indexing) {
+ psv->InsertValue(0, 10, 0);
+ psv->SetValueAt(5, 3);
+ EXPECT_EQ(10, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i == 5) ? 3 : 0, (*psv)[i]);
+ }
+}
+
+TEST_F(SplitVectorTest, Fill) {
+ psv->InsertValue(0, 10, 0);
+ EXPECT_EQ(10, psv->Length());
+ psv->InsertValue(7, 1, 1);
+ EXPECT_EQ(11, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i == 7) ? 1 : 0, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, DeleteOne) {
+ psv->InsertFromArray(0, testArray, 0, lengthTestArray);
+ psv->Delete(2);
+ EXPECT_EQ(lengthTestArray-1, psv->Length());
+ EXPECT_EQ(3, (*psv)[0]);
+ EXPECT_EQ(4, (*psv)[1]);
+ EXPECT_EQ(6, (*psv)[2]);
+}
+
+TEST_F(SplitVectorTest, DeleteRange) {
+ psv->InsertValue(0, 10, 0);
+ EXPECT_EQ(10, psv->Length());
+ psv->InsertValue(7, 1, 1);
+ EXPECT_EQ(11, psv->Length());
+ psv->DeleteRange(2, 3);
+ EXPECT_EQ(8, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i == 4) ? 1 : 0, psv->ValueAt(i));
+ }
+}
+
+TEST_F(SplitVectorTest, DeleteAll) {
+ psv->InsertValue(0, 10, 0);
+ psv->InsertValue(7, 1, 1);
+ psv->DeleteRange(2, 3);
+ psv->DeleteAll();
+ EXPECT_EQ(0, psv->Length());
+}
+
+TEST_F(SplitVectorTest, GetRange) {
+ psv->InsertValue(0, 10, 0);
+ psv->InsertValue(7, 1, 1);
+ int retrieveArray[11] = {0};
+ psv->GetRange(retrieveArray, 0, 11);
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ((i==7) ? 1 : 0, retrieveArray[i]);
+ }
+}
+
+TEST_F(SplitVectorTest, GetRangeOverGap) {
+ psv->InsertFromArray(0, testArray, 0, lengthTestArray);
+ EXPECT_EQ(lengthTestArray, psv->Length());
+ int retrieveArray[lengthTestArray] = {0};
+ psv->GetRange(retrieveArray, 0, lengthTestArray);
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(i+3, retrieveArray[i]);
+ }
+}
+
+TEST_F(SplitVectorTest, ReplaceUp) {
+ // Replace each element by inserting and then deleting the displaced element
+ // This should perform many moves
+ const int testLength=105;
+ psv->EnsureLength(testLength);
+ for (int i=0; i<testLength; i++)
+ psv->SetValueAt(i, i+2);
+ EXPECT_EQ(testLength, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ psv->InsertValue(i, 1, i+9);
+ psv->Delete(i+1);
+ }
+ for (int i=0; i<psv->Length(); i++)
+ EXPECT_EQ(i+9, psv->ValueAt(i));
+}
+
+TEST_F(SplitVectorTest, ReplaceDown) {
+ // From the end, replace each element by inserting and then deleting the displaced element
+ // This should perform many moves
+ const int testLength=24;
+ psv->EnsureLength(testLength);
+ for (int i=0; i<testLength; i++)
+ psv->SetValueAt(i, i+12);
+ EXPECT_EQ(testLength, psv->Length());
+ for (int i=psv->Length()-1; i>=0; i--) {
+ psv->InsertValue(i, 1, i+5);
+ psv->Delete(i+1);
+ }
+ for (int i=0; i<psv->Length(); i++)
+ EXPECT_EQ(i+5, psv->ValueAt(i));
+}
+
+TEST_F(SplitVectorTest, BufferPointer) {
+ psv->InsertFromArray(0, testArray, 0, lengthTestArray);
+ int *retrievePointer = psv->BufferPointer();
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(i+3, retrievePointer[i]);
+ }
+}
+
+TEST_F(SplitVectorTest, DeleteBackAndForth) {
+ psv->InsertValue(0, 10, 87);
+ for (int i=0; i<10; i+=2) {
+ int len = 10 - i;
+ EXPECT_EQ(len, psv->Length());
+ for (int i=0; i<psv->Length(); i++) {
+ EXPECT_EQ(87, psv->ValueAt(i));
+ }
+ psv->Delete(len-1);
+ psv->Delete(0);
+ }
+}
+
+TEST_F(SplitVectorTest, GrowSize) {
+ psv->SetGrowSize(5);
+ EXPECT_EQ(5, psv->GetGrowSize());
+}
+
+TEST_F(SplitVectorTest, OutsideBounds) {
+ psv->InsertValue(0, 10, 87);
+ EXPECT_EQ(0, psv->ValueAt(-1));
+ EXPECT_EQ(0, psv->ValueAt(10));
+
+ /* Could be a death test as this asserts:
+ psv->SetValueAt(-1,98);
+ psv->SetValueAt(10,99);
+ EXPECT_EQ(0, psv->ValueAt(-1));
+ EXPECT_EQ(0, psv->ValueAt(10));
+ */
+}
diff --git a/test/unit/unitTest.cxx b/test/unit/unitTest.cxx
new file mode 100644
index 000000000..e1bb7bad2
--- /dev/null
+++ b/test/unit/unitTest.cxx
@@ -0,0 +1,50 @@
+// Unit Tests for Scintilla internal data structures
+
+/*
+ Currently tested:
+ SplitVector
+ Partitioning
+ ContractionState
+
+ To do:
+ RunStyles
+ Decoration
+ DecorationList
+ PerLine *
+ CellBuffer *
+ Range
+ StyledText
+ CaseFolder ...
+ Document
+ RESearch
+ Selection
+ UniConversion
+ Style
+
+ lexlib:
+ Accessor
+ LexAccessor
+ CharacterSet
+ OptionSet
+ PropSetSimple
+ StyleContext
+ WordList
+*/
+
+#include <stdio.h>
+
+#include "Platform.h"
+
+#include <gtest/gtest.h>
+
+// Needed for PLATFORM_ASSERT in code being tested
+
+void Platform::Assert(const char *c, const char *file, int line) {
+ fprintf(stderr, "Assertion [%s] failed at %s %d\n", c, file, line);
+ abort();
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}