Improve UIA movement testing methodology (#10886)
Introduces a new methodology to maintain tests for UI Automation. This includes... - `UiaTests.csv`: an excel spreadsheet designed to store UIA movement tests in a compact format - `GeneratedTests.ps1`: a PowerShell script that imports `UiaTests.csv` and outputs a C++ TEST_METHOD for `UiaTextRangeTests. This new system can be used to easily add more UIA movement tests. Read https://github.com/microsoft/terminal/blob/dev/cazamor/a11y-7000/testing/tools/TestTableWriter/README.md for more details. Follow-up work items: - #10924 **Failing Tests**: this found some failing tests. We should make them not fail. - #10925 **Missing Tests: Word navigation**: Word navigation is missing. - #10926 **MoveEndpoint Tests**: an additional column can be added to the CSV "EndpointTarget", which can be "start", "end", or "both". This will allow us to test `MoveEndpoint` in addition to `Move`.
This commit is contained in:
parent
482dcec60a
commit
1678b58dde
2
.github/actions/spelling/allow/allow.txt
vendored
2
.github/actions/spelling/allow/allow.txt
vendored
|
@ -33,6 +33,7 @@ kje
|
|||
liga
|
||||
lje
|
||||
locl
|
||||
lorem
|
||||
maxed
|
||||
mkmk
|
||||
mru
|
||||
|
@ -59,6 +60,7 @@ TLDR
|
|||
tokenizes
|
||||
tonos
|
||||
tshe
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
unregister
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,8 @@
|
|||
#include "../../../buffer/out/textBuffer.hpp"
|
||||
#include "../types/UiaTracing.h"
|
||||
|
||||
#include <IDataSource.h>
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
@ -19,13 +21,193 @@ using namespace Microsoft::WRL;
|
|||
|
||||
using namespace Microsoft::Console::Interactivity::Win32;
|
||||
|
||||
static constexpr til::point point_offset_by_char(const til::point start, const til::rectangle bounds, ptrdiff_t amt)
|
||||
{
|
||||
ptrdiff_t pos_x = start.x();
|
||||
ptrdiff_t pos_y = start.y();
|
||||
while (amt != 0)
|
||||
{
|
||||
if (amt > 0)
|
||||
{
|
||||
if (pos_x == bounds.left() && pos_y == bounds.bottom())
|
||||
{
|
||||
// end exclusive --> can't move any more
|
||||
break;
|
||||
}
|
||||
else if (pos_x == bounds.right() - 1)
|
||||
{
|
||||
// right boundary --> wrap
|
||||
pos_x = bounds.left();
|
||||
++pos_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// standard move
|
||||
++pos_x;
|
||||
}
|
||||
--amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos_x == bounds.left() && pos_y == bounds.top())
|
||||
{
|
||||
// origin --> can't move any more
|
||||
break;
|
||||
}
|
||||
else if (pos_x == bounds.left())
|
||||
{
|
||||
// left boundary --> wrap
|
||||
pos_x = bounds.right() - 1;
|
||||
--pos_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// standard move
|
||||
--pos_x;
|
||||
}
|
||||
++amt;
|
||||
}
|
||||
}
|
||||
return { pos_x, pos_y };
|
||||
}
|
||||
|
||||
static constexpr til::point point_offset_by_line(const til::point start, const til::rectangle bounds, ptrdiff_t amt)
|
||||
{
|
||||
// X = left boundary for UIA
|
||||
ptrdiff_t pos_x = bounds.left();
|
||||
ptrdiff_t pos_y = start.y();
|
||||
while (amt != 0)
|
||||
{
|
||||
if (amt > 0)
|
||||
{
|
||||
if (pos_y == bounds.bottom() + 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos_y;
|
||||
}
|
||||
--amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos_y == bounds.top())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
--pos_y;
|
||||
}
|
||||
++amt;
|
||||
}
|
||||
}
|
||||
return { pos_x, pos_y };
|
||||
}
|
||||
|
||||
// IMPORTANT: reference this _after_ defining point_offset_by_XXX. We need it for some definitions
|
||||
#include "GeneratedUiaTextRangeMovementTests.g.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
#pragma region TAEF hookup for the test case array above
|
||||
struct ArrayIndexTaefAdapterRow : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataRow>
|
||||
{
|
||||
HRESULT RuntimeClassInitialize(const size_t index)
|
||||
{
|
||||
_index = index;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestData(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
const auto indexString{ wil::str_printf<std::wstring>(L"%zu", _index) };
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto indexBstr{ wil::make_bstr(indexString.c_str()) };
|
||||
(void)SafeArrayPutElement(safeArray, &index, indexBstr.release());
|
||||
*ppData = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadataNames(SAFEARRAY** ppMetadataNames) override
|
||||
{
|
||||
*ppMetadataNames = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadata(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
*ppData = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetName(BSTR* ppszRowName) override
|
||||
{
|
||||
*ppszRowName = wil::make_bstr(s_movementTests[_index].name.data()).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
struct ArrayIndexTaefAdapterSource : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataSource>
|
||||
{
|
||||
STDMETHODIMP Advance(IDataRow** ppDataRow) override
|
||||
{
|
||||
if (_index < s_movementTests.size())
|
||||
{
|
||||
Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterRow>(ppDataRow, _index++);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDataRow = nullptr;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset() override
|
||||
{
|
||||
_index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataNames(SAFEARRAY** names) override
|
||||
{
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto dataNameBstr{ wil::make_bstr(L"index") };
|
||||
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.release());
|
||||
*names = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataType(BSTR /*name*/, BSTR* type) override
|
||||
{
|
||||
*type = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index{ 0 };
|
||||
};
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
extern "C" HRESULT __declspec(dllexport) __cdecl GeneratedMovementTestDataSource(IDataSource** ppDataSource, void*)
|
||||
{
|
||||
auto source{ Microsoft::WRL::Make<ArrayIndexTaefAdapterSource>() };
|
||||
return source.CopyTo(ppDataSource);
|
||||
}
|
||||
|
||||
// UiaTextRange takes an object that implements
|
||||
// IRawElementProviderSimple as a constructor argument. Making a real
|
||||
// one would involve setting up the window which we don't want to do
|
||||
// for unit tests so instead we'll use this one. We don't care about
|
||||
// it not doing anything for its implementation because it is not used
|
||||
// during the unit tests below.
|
||||
|
||||
class DummyElementProvider final : public ScreenInfoUiaProviderBase
|
||||
{
|
||||
public:
|
||||
|
@ -197,9 +379,6 @@ class UiaTextRangeTests
|
|||
|
||||
TEST_METHOD(DegenerateRangesDetected)
|
||||
{
|
||||
const auto bufferSize = _pTextBuffer->GetSize();
|
||||
const auto origin = bufferSize.Origin();
|
||||
|
||||
// make a degenerate range and verify that it reports degenerate
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> degenerate;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(°enerate,
|
||||
|
@ -211,7 +390,7 @@ class UiaTextRangeTests
|
|||
VERIFY_ARE_EQUAL(degenerate->_start, degenerate->_end);
|
||||
|
||||
// make a non-degenerate range and verify that it reports as such
|
||||
const COORD end = { origin.X + 1, origin.Y };
|
||||
const auto end{ point_offset_by_char(origin, bufferSize, 1) };
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> notDegenerate;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(¬Degenerate,
|
||||
_pUiaData,
|
||||
|
@ -224,9 +403,6 @@ class UiaTextRangeTests
|
|||
|
||||
TEST_METHOD(CompareRange)
|
||||
{
|
||||
const auto bufferSize = _pTextBuffer->GetSize();
|
||||
const auto origin = bufferSize.Origin();
|
||||
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> utr1;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr1,
|
||||
_pUiaData,
|
||||
|
@ -244,7 +420,7 @@ class UiaTextRangeTests
|
|||
VERIFY_IS_TRUE(comparison);
|
||||
|
||||
// utr2 redefined to have different end from utr1
|
||||
const COORD end = { origin.X + 2, origin.Y };
|
||||
const auto end{ point_offset_by_char(origin, bufferSize, 2) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr2,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
|
@ -258,9 +434,6 @@ class UiaTextRangeTests
|
|||
|
||||
TEST_METHOD(CompareEndpoints)
|
||||
{
|
||||
const auto bufferSize = _pTextBuffer->GetSize();
|
||||
const auto origin = bufferSize.Origin();
|
||||
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> utr1;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr1,
|
||||
_pUiaData,
|
||||
|
@ -283,7 +456,7 @@ class UiaTextRangeTests
|
|||
VERIFY_IS_TRUE(comparison == 0);
|
||||
|
||||
// utr2 redefined to have different end from utr1
|
||||
const COORD end = { origin.X + 2, origin.Y };
|
||||
const auto end{ point_offset_by_char(origin, bufferSize, 2) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr2,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
|
@ -465,8 +638,6 @@ class UiaTextRangeTests
|
|||
start,
|
||||
end));
|
||||
|
||||
const auto bufferSize = _pTextBuffer->GetSize();
|
||||
const auto origin = bufferSize.Origin();
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> target;
|
||||
|
||||
auto resetTargetUTR = [&]() {
|
||||
|
@ -1137,9 +1308,7 @@ class UiaTextRangeTests
|
|||
// at the end exclusive, the UTR should refuse to move past
|
||||
// the end.
|
||||
|
||||
const auto bufferSize{ _pTextBuffer->GetSize() };
|
||||
const til::point endInclusive{ bufferSize.RightInclusive(), bufferSize.BottomInclusive() };
|
||||
const auto endExclusive{ bufferSize.EndExclusive() };
|
||||
const til::point endInclusive{ bufferEnd };
|
||||
|
||||
// Iterate over each TextUnit. If the we don't support
|
||||
// the given TextUnit, we're supposed to fallback
|
||||
|
@ -1153,7 +1322,7 @@ class UiaTextRangeTests
|
|||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, endInclusive, endExclusive));
|
||||
THROW_IF_FAILED(utr->ExpandToEnclosingUnit(static_cast<TextUnit>(unit)));
|
||||
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1162,12 +1331,9 @@ class UiaTextRangeTests
|
|||
// GH#7663: When attempting to move from end exclusive,
|
||||
// the UTR should refuse to move past the end.
|
||||
|
||||
const auto bufferSize{ _pTextBuffer->GetSize() };
|
||||
const COORD origin{ bufferSize.Origin() };
|
||||
const COORD lastLineStart{ bufferSize.Left(), bufferSize.BottomInclusive() };
|
||||
const COORD secondToLastCharacterPos{ bufferSize.RightInclusive() - 1, bufferSize.BottomInclusive() };
|
||||
const COORD endInclusive{ bufferSize.RightInclusive(), bufferSize.BottomInclusive() };
|
||||
const COORD endExclusive{ bufferSize.EndExclusive() };
|
||||
const auto lastLineStart{ bufferEndLeft };
|
||||
const auto secondToLastCharacterPos{ point_offset_by_char(bufferEnd, bufferSize, -1) };
|
||||
const auto endInclusive{ bufferEnd };
|
||||
|
||||
// Iterate over each TextUnit. If we don't support
|
||||
// the given TextUnit, we're supposed to fallback
|
||||
|
@ -1198,11 +1364,11 @@ class UiaTextRangeTests
|
|||
}
|
||||
THROW_IF_FAILED(utr->Move(textUnit, 1, &moveAmt));
|
||||
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
VERIFY_ARE_EQUAL(0, moveAmt);
|
||||
|
||||
// write "temp" at (2,2)
|
||||
const COORD writeTarget{ 2, 2 };
|
||||
const til::point writeTarget{ 2, 2 };
|
||||
_pTextBuffer->Write({ L"temp" }, writeTarget);
|
||||
|
||||
// Verify expansion works properly
|
||||
|
@ -1210,23 +1376,23 @@ class UiaTextRangeTests
|
|||
THROW_IF_FAILED(utr->ExpandToEnclosingUnit(textUnit));
|
||||
if (textUnit <= TextUnit::TextUnit_Character)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(endInclusive, utr->_start);
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(endInclusive, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Word)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(writeTarget, utr->_start);
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(writeTarget, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Line)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(lastLineStart, utr->_start);
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
else // textUnit <= TextUnit::TextUnit_Document:
|
||||
{
|
||||
VERIFY_ARE_EQUAL(origin, utr->_start);
|
||||
VERIFY_ARE_EQUAL(endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
|
||||
// reset the UTR
|
||||
|
@ -1250,23 +1416,23 @@ class UiaTextRangeTests
|
|||
// Special case: _end will always be endInclusive, because...
|
||||
// - degenerate --> it moves with _start to stay degenerate
|
||||
// - !degenerate --> it excludes the last char, to select the second to last char
|
||||
VERIFY_ARE_EQUAL(degenerate ? endInclusive : secondToLastCharacterPos, utr->_start);
|
||||
VERIFY_ARE_EQUAL(endInclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(degenerate ? endInclusive : secondToLastCharacterPos, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(endInclusive, til::point{ utr->_end });
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Word)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(origin, utr->_start);
|
||||
VERIFY_ARE_EQUAL(degenerate ? origin : writeTarget, utr->_end);
|
||||
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(degenerate ? origin : writeTarget, til::point{ utr->_end });
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Line)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(lastLineStart, utr->_start);
|
||||
VERIFY_ARE_EQUAL(degenerate ? lastLineStart : endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(degenerate ? lastLineStart : endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
else // textUnit <= TextUnit::TextUnit_Document:
|
||||
{
|
||||
VERIFY_ARE_EQUAL(origin, utr->_start);
|
||||
VERIFY_ARE_EQUAL(degenerate ? origin : endExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(degenerate ? origin : endExclusive, til::point{ utr->_end });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,9 +1440,7 @@ class UiaTextRangeTests
|
|||
{
|
||||
// See GH#7742 for more details.
|
||||
|
||||
const auto bufferSize{ _pTextBuffer->GetSize() };
|
||||
const COORD origin{ bufferSize.Origin() };
|
||||
const COORD originExclusive{ origin.X, origin.Y + 1 };
|
||||
const auto originExclusive{ point_offset_by_char(origin, bufferSize, 1) };
|
||||
|
||||
_pTextBuffer->Write({ L"My name is Carlos" }, origin);
|
||||
|
||||
|
@ -1314,21 +1478,20 @@ class UiaTextRangeTests
|
|||
|
||||
TEST_METHOD(ScrollIntoView)
|
||||
{
|
||||
const auto bufferSize{ _pTextBuffer->GetSize() };
|
||||
const auto viewportSize{ _pUiaData->GetViewport() };
|
||||
|
||||
const std::vector<ScrollTest> testData{
|
||||
{ L"Origin", bufferSize.Top() },
|
||||
{ L"ViewportHeight From Top - 1", bufferSize.Top() + viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Top", bufferSize.Top() + viewportSize.Height() },
|
||||
{ L"ViewportHeight From Top + 1", bufferSize.Top() + viewportSize.Height() + 1 },
|
||||
{ L"ViewportHeight From Bottom - 1", bufferSize.BottomInclusive() - viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Bottom", bufferSize.BottomInclusive() - viewportSize.Height() },
|
||||
{ L"ViewportHeight From Bottom + 1", bufferSize.BottomInclusive() - viewportSize.Height() + 1 },
|
||||
{ L"Origin", gsl::narrow<short>(bufferSize.top()) },
|
||||
{ L"ViewportHeight From Top - 1", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Top", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() },
|
||||
{ L"ViewportHeight From Top + 1", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() + 1 },
|
||||
{ L"ViewportHeight From Bottom - 1", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() - 2 },
|
||||
{ L"ViewportHeight From Bottom", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Bottom + 1", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() + 1 },
|
||||
|
||||
// GH#7839: ExclusiveEnd is a non-existent space,
|
||||
// so scrolling to it when !alignToTop used to crash
|
||||
{ L"Exclusive End", bufferSize.BottomExclusive() }
|
||||
{ L"Exclusive End", gsl::narrow<short>(bufferSize.bottom()) }
|
||||
};
|
||||
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
|
@ -1342,7 +1505,7 @@ class UiaTextRangeTests
|
|||
for (const auto test : testData)
|
||||
{
|
||||
Log::Comment(test.comment.c_str());
|
||||
const til::point pos{ bufferSize.Left(), test.yPos };
|
||||
const til::point pos{ bufferSize.left(), test.yPos };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, pos, pos));
|
||||
VERIFY_SUCCEEDED(utr->ScrollIntoView(alignToTop));
|
||||
}
|
||||
|
@ -1663,4 +1826,140 @@ class UiaTextRangeTests
|
|||
UiaTextRange* cloneUtr2 = static_cast<UiaTextRange*>(clone2.Get());
|
||||
VERIFY_IS_TRUE(cloneUtr2->_blockRange);
|
||||
}
|
||||
|
||||
TEST_METHOD(Movement)
|
||||
{
|
||||
// Helpful variables
|
||||
const auto firstChar{ point_offset_by_char(origin, bufferSize, 1) };
|
||||
const auto secondChar{ point_offset_by_char(origin, bufferSize, 2) };
|
||||
const auto fifthChar{ point_offset_by_char(origin, bufferSize, 5) };
|
||||
const auto sixthChar{ point_offset_by_char(origin, bufferSize, 6) };
|
||||
const til::point documentEnd{ bufferSize.left(), (bufferSize.height() / 2) + 1 };
|
||||
|
||||
// Populate buffer
|
||||
// Split the line into 5 segments alternating between "X" and whitespace
|
||||
// _________________
|
||||
// |XXX XXX XXX|
|
||||
// |XXX XXX XXX|
|
||||
// |XXX XXX XXX|
|
||||
// |XXX XXX XXX|
|
||||
// |_______________|
|
||||
{
|
||||
short i = 0;
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(origin) };
|
||||
const auto segment{ bufferSize.width() / 5 };
|
||||
while (iter.Pos() != documentEnd)
|
||||
{
|
||||
bool fill{ true };
|
||||
if (i % segment == 0)
|
||||
{
|
||||
fill = !fill;
|
||||
}
|
||||
|
||||
if (fill)
|
||||
{
|
||||
_pTextBuffer->Write({ L"X" }, iter.Pos());
|
||||
}
|
||||
|
||||
++i;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
// Define tests
|
||||
struct TestInput
|
||||
{
|
||||
TextUnit unit;
|
||||
int moveAmt;
|
||||
til::point start;
|
||||
til::point end;
|
||||
};
|
||||
|
||||
struct TestOutput
|
||||
{
|
||||
int moveAmt;
|
||||
til::point start;
|
||||
til::point end;
|
||||
};
|
||||
|
||||
struct MyTest
|
||||
{
|
||||
std::wstring name;
|
||||
TestInput input;
|
||||
TestOutput output;
|
||||
};
|
||||
|
||||
const std::vector<MyTest> tests{
|
||||
MyTest{ L"Degenerate at origin", TestInput{ TextUnit_Character, -5, origin, origin }, TestOutput{ 0, origin, origin } }
|
||||
};
|
||||
}
|
||||
|
||||
TEST_METHOD(GeneratedMovementTests)
|
||||
{
|
||||
// Populate the buffer with...
|
||||
// - 9 segments of alternating text
|
||||
// - up to half of the buffer (vertically)
|
||||
// It'll look something like this
|
||||
// +---------------------------+
|
||||
// |XXX XXX XXX XXX XXX|
|
||||
// |XXX XXX XXX XXX XXX|
|
||||
// |XXX XXX XXX XXX XXX|
|
||||
// |XXX XXX XXX XXX XXX|
|
||||
// |XXX XXX XXX XXX XXX|
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// +---------------------------+
|
||||
{
|
||||
short i = 0;
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin()) };
|
||||
const auto segment{ bufferSize.width() / 9 };
|
||||
while (iter.Pos() != docEnd)
|
||||
{
|
||||
bool fill{ true };
|
||||
if (i % segment == 0)
|
||||
{
|
||||
fill = !fill;
|
||||
}
|
||||
|
||||
if (fill)
|
||||
{
|
||||
_pTextBuffer->Write({ L"X" }, iter.Pos());
|
||||
}
|
||||
|
||||
++i;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"DataSource", L"Export:GeneratedMovementTestDataSource")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
|
||||
WEX::TestExecution::SetVerifyOutput verifyOutputScope{ WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures };
|
||||
|
||||
unsigned int i{};
|
||||
TestData::TryGetValue(L"index", i); // index is produced by the ArrayIndexTaefAdapterSource above
|
||||
const auto& testCase{ s_movementTests[i] };
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"[%zu.0] Test case \"%.*s\"", i, testCase.name.size(), testCase.name.data()));
|
||||
if (testCase.skip)
|
||||
{
|
||||
Log::Result(WEX::Logging::TestResults::Result::Skipped);
|
||||
}
|
||||
else
|
||||
{
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> utr;
|
||||
int amountMoved;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, testCase.input.start, testCase.input.end));
|
||||
THROW_IF_FAILED(utr->Move(testCase.input.unit, testCase.input.moveAmount, &amountMoved));
|
||||
|
||||
VERIFY_ARE_EQUAL(testCase.expected.moveAmount, amountMoved);
|
||||
VERIFY_ARE_EQUAL(testCase.expected.start, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(testCase.expected.end, til::point{ utr->_end });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
164
tools/TestTableWriter/GenerateTests.ps1
Normal file
164
tools/TestTableWriter/GenerateTests.ps1
Normal file
|
@ -0,0 +1,164 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
################################################################################
|
||||
# This script generates the an array of UiaTextRange tests suitable for replacing the body of
|
||||
# src\interactivity\win32\ut_interactivity_win32\UiaTextRangeTests.cpp TEST_METHOD(GeneratedMovementTests)
|
||||
#
|
||||
# See tools\TestTableWriter\README.md for more details on how to use this script.
|
||||
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Position=0, ValueFromPipeline=$true)]
|
||||
[string]$TestPath = "UiaTests.csv"
|
||||
)
|
||||
|
||||
# 0. Generate a comment telling people to not modify these tests in the .cpp
|
||||
$result = "// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// DO NOT MODIFY THESE TESTS DIRECTLY
|
||||
// These were generated by tools\TestTableWriter\GenerateTests.ps1
|
||||
// Read tools\TestTableWriter\README.md for more details"
|
||||
|
||||
# TODO: THIS IS PROBABLY WRONG. Bottom/Right are exclusive (I think?)
|
||||
# 1. Define a few helpful variables to make life easier.
|
||||
$result += "
|
||||
// Define a few helpful variables
|
||||
constexpr til::rectangle bufferSize{ 0, 0, 80, 300 };
|
||||
constexpr short midX{ 40 };
|
||||
constexpr short midY{ 150 };
|
||||
constexpr short midPopulatedY{ 75 };
|
||||
constexpr til::point origin{ 0, 0 };
|
||||
constexpr til::point midTop{ midX, 0 };
|
||||
constexpr til::point midHistory{ midX, midPopulatedY };
|
||||
constexpr til::point midDocEnd{ midX, midY };
|
||||
constexpr til::point lastCharPos{ 79, midY };
|
||||
constexpr til::point docEnd{ 0, midY + 1 };
|
||||
constexpr til::point midEmptySpace{ midX, midY + midPopulatedY };
|
||||
constexpr til::point bufferEnd{ 79, 299 };
|
||||
constexpr til::point endExclusive{ 0, 300 };`n"
|
||||
|
||||
# 2. Import the CSV test file and find all of the variables we need
|
||||
$tests = Import-Csv $TestPath;
|
||||
$vars = New-Object System.Collections.Generic.SortedSet[string];
|
||||
foreach ($test in $tests)
|
||||
{
|
||||
$vars.Add($test.Start) > $null;
|
||||
$vars.Add($test.End) > $null;
|
||||
$vars.Add($test.Result_Start) > $null;
|
||||
$vars.Add($test.Result_End) > $null;
|
||||
}
|
||||
|
||||
# 3. Define each of the vars
|
||||
# 3.a. Some of the variables were already defined at the beginning. So let's remove those.
|
||||
$vars.Remove("origin") > $null;
|
||||
$vars.Remove("midTop") > $null;
|
||||
$vars.Remove("midHistory") > $null;
|
||||
$vars.Remove("docEnd") > $null;
|
||||
|
||||
# 3.b. Now all of the remaining vars can be deduced from standard vars
|
||||
foreach ($var in $vars)
|
||||
{
|
||||
# Extract the standard var from the name
|
||||
$standardVar = $var.Contains("Left") ? $var.Split("Left") : $var.Substring(0, $var.length - 3);
|
||||
|
||||
# i. Contains number --> requires movement
|
||||
if ($var -match ".*\d+.*")
|
||||
{
|
||||
# 3rd to last character denotes the movement direction
|
||||
# P --> plus/forwards
|
||||
# M --> minus/backwards
|
||||
$moveForward = $var.substring($var.length - 3, 1) -eq 'P';
|
||||
|
||||
# 2nd to last character denotes the movement amount
|
||||
$moveAmt = $var.substring($var.length -2, 1);
|
||||
|
||||
# last character denotes the movement type
|
||||
switch ($var.substring($var.length - 1, 1)) {
|
||||
'C' # move by character
|
||||
{
|
||||
if ($moveForward)
|
||||
{
|
||||
$result += "constexpr auto {0}{{ point_offset_by_char({1}, bufferSize, {2}) }};" -f $var, $standardVar, $moveAmt;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result += "constexpr auto {0}{{ point_offset_by_char({1}, bufferSize, -{2}) }};" -f $var, $standardVar, $moveAmt;
|
||||
}
|
||||
}
|
||||
'L' # move by line
|
||||
{
|
||||
if ($moveForward)
|
||||
{
|
||||
$result += "constexpr auto {0}{{ point_offset_by_line({1}, bufferSize, {2}) }};" -f $var, $standardVar, $moveAmt;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result += "constexpr auto {0}{{ point_offset_by_line({1}, bufferSize, -{2}) }};" -f $var, $standardVar, $moveAmt;
|
||||
}
|
||||
}
|
||||
Default { Write-Host "Error: unknown variable movement type" -ForegroundColor Red }
|
||||
}
|
||||
}
|
||||
# ii. Contains "Left" --> set X to left
|
||||
elseif ($var.Contains("Left"))
|
||||
{
|
||||
$result += "constexpr til::point " + $var + "{ bufferSize.left(), " + $standardVar + ".y() };";
|
||||
}
|
||||
$result += "`n";
|
||||
}
|
||||
|
||||
# 4. Write the tests
|
||||
# 4.a. Introduce a struct to store each test as
|
||||
$result += "struct GeneratedMovementTestInput
|
||||
{
|
||||
TextUnit unit;
|
||||
int moveAmount;
|
||||
til::point start;
|
||||
til::point end;
|
||||
};
|
||||
struct GeneratedMovementTestExpected
|
||||
{
|
||||
int moveAmount;
|
||||
til::point start;
|
||||
til::point end;
|
||||
};
|
||||
struct GeneratedMovementTest
|
||||
{
|
||||
std::wstring_view name;
|
||||
GeneratedMovementTestInput input;
|
||||
GeneratedMovementTestExpected expected;
|
||||
bool skip;
|
||||
};`n`n";
|
||||
|
||||
# 4.b. Iterate through CSV file and generate a test for each one
|
||||
$result += "static constexpr std::array<GeneratedMovementTest, {0}> s_movementTests`n{{`n" -f $tests.count;
|
||||
foreach ($test in $tests)
|
||||
{
|
||||
$degeneratePrefix = $test.degenerate -eq "TRUE" ? "" : "non-";
|
||||
$movementType = $test.TextUnit.substring(9);
|
||||
$testName = "L`"Move {0}degenerate range at position {1} {2} times by {3}`"" -f $degeneratePrefix, $test.Position, $test.MoveAmount, $movementType;
|
||||
$testInput = "GeneratedMovementTestInput{{
|
||||
TextUnit::{0},
|
||||
{1},
|
||||
{2},
|
||||
{3}
|
||||
}}" -f $test.TextUnit, $test.MoveAmount, $test.Start, $test.End;
|
||||
$testExpected = "GeneratedMovementTestExpected{{
|
||||
{0},
|
||||
{1},
|
||||
{2}
|
||||
}}" -f $test.Result_MoveAmount, $test.Result_Start, $test.Result_End;
|
||||
$skip = $test.Skip -eq "TRUE" ? "true" : "false";
|
||||
|
||||
$result += " GeneratedMovementTest{{
|
||||
{0},
|
||||
{1},
|
||||
{2},
|
||||
{3}
|
||||
}},`n" -f $testName, $testInput, $testExpected, $skip;
|
||||
}
|
||||
$result += "};`n`n"
|
||||
|
||||
$result > "..\..\src\interactivity\win32\ut_interactivity_win32\GeneratedUiaTextRangeMovementTests.g.cpp";
|
90
tools/TestTableWriter/README.md
Normal file
90
tools/TestTableWriter/README.md
Normal file
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
author: Carlos Zamora @carlos-zamora
|
||||
created on: 2021-08-05
|
||||
last updated: 2021-08-05
|
||||
---
|
||||
|
||||
# Test Table Writer
|
||||
|
||||
The Test Table Writer was written as a method to generate UI Automation tests for OpenConsole. UI Automation has a lot of corner cases, so we developed this workflow to simplify storing and updating these test cases (particularly revolving around movement).
|
||||
|
||||
# How to use it
|
||||
1. Update `UiaTests.csv`:
|
||||
- This file is used to store the tests in a compact format. The defined columns include...
|
||||
- Degenerate: is this a degenerate range?
|
||||
- Position: see the position chart below
|
||||
- TextUnit: what text unit to move by
|
||||
- MoveAmount: how many times to move
|
||||
- Start: the start endpoint of the text range. Represented by a variable name used to signify a position in the buffer. See the variable heuristics section below.
|
||||
- End: the start endpoint of the text range. Represented by a variable name used to signify a position in the buffer. See the variable heuristics section below.
|
||||
- Result_MoveAmount: the expected amount to have moved by
|
||||
- Result_Start: the expected position of the start endpoint after executing the move operation
|
||||
- Result_End: the expected position of the end endpoint after executing the move operation
|
||||
- Skip: skip the test. Can be used for failing tests.
|
||||
- Each row represents a new test in a compact format.
|
||||
- Use the position chart and the variable heuristics below to add more tests easily.
|
||||
2. Run `GenerateTests.ps1`
|
||||
- `GenerateTests.ps1` will load `UiaTests.csv` and export the tests and any necessary variables to "src\interactivity\win32\ut_interactivity_win32\GeneratedUiaTextRangeMovementTests.g.cpp".
|
||||
3. Build and run the tests
|
||||
- Build UiaTextRangeTests
|
||||
- Go to bin\x64\Debug
|
||||
- Run `clear; .\TE.exe /name:*UiaTextRangeTests*GeneratedMovementTests* .\Conhost.Interactivity.Win32.Unit.Tests.dll` in PowerShell
|
||||
5. If the tests pass, upload any changes to `UiaTests.csv` and `GeneratedUiaTextRangeMovementTests.g.cpp`. Be sure to run the code formatter.
|
||||
|
||||
# Helpful tips
|
||||
- How to verify a test is authored correctly
|
||||
- use MS Word to generate some text (try typing "=lorem(5,5)" then pressing enter to generate text)
|
||||
- use Accessibility Insights to run the UIA API on MS Word's ITextProvider
|
||||
- if you create a selection (or move the cursor), then tell Accessibility Insights to get the "Selection" range (or refresh it), you can easily set up a test case
|
||||
- Run the tests via Visual Studio
|
||||
- In the Solution Explorer, right-click Interactivity.Win32.Tests.Unit and select "Set as Startup Project"
|
||||
- right-click it again and select "Properties"
|
||||
- In the Debugging section, set..
|
||||
- "Command" --> `$(OutDir)/TE.exe`
|
||||
- "Command Arguments" --> `$(TargetPath) /name:*uiatextrange*generated* /inproc`
|
||||
|
||||
# Position chart
|
||||
The text buffer is assumed to be partially filled. Specifically, the top half of the text buffer contains text, and each row is filled with 9 segments of alternating text. For visualization,
|
||||
the ascii diagram below shows what the text buffer may look like.
|
||||
```
|
||||
+---------------------------+
|
||||
|1XX XXX X2X XXX XXX|
|
||||
|XXX XXX XXX XXX XXX|
|
||||
|XXX XXX X3X XXX XXX|
|
||||
|XXX XXX XXX XXX XXX|
|
||||
|XXX XXX X4X XXX XX5|
|
||||
|6 |
|
||||
| |
|
||||
| 7 |
|
||||
| |
|
||||
| 8|
|
||||
+---------------------------+
|
||||
9
|
||||
```
|
||||
The following positions are being tested:
|
||||
1. `origin`: buffer origin
|
||||
2. `midTop`: middle of the top line
|
||||
3. `midHistory`: middle of the history
|
||||
4. `midDocEnd`: middle of the last line of text
|
||||
5. `lastCharPos`: last character in the buffer
|
||||
6. `docEnd`: one past the last line of text
|
||||
7. `midEmptySpace`: middle of the empty space in the buffer
|
||||
8. `bufferEnd`: end of the buffer
|
||||
9. `endExclusive`: exclusive end of the buffer
|
||||
|
||||
This is intended to provide adequate testing coverage for GH#6986.
|
||||
|
||||
# Variable Heuristics
|
||||
Each position above already has a predefined variable name. However, a few heuristics are used to define new variables based on the standard variables above.
|
||||
- `<name>Left`: the left-most position on the same line as `<name>`
|
||||
- `<name>P<number>C`, `<name>M<number>C`:
|
||||
- `<name>`: start at the position of `<name>`
|
||||
- `P` (or `M`): move forwards (aka "plus") by a certain amount (`M` is used to move backwards [aka "minus"])
|
||||
- `<number>`: how much to move forwards by
|
||||
- `C`: move by character. For simplicity, assumes that each character is one-cell wide.
|
||||
- `<name>P<number>L`, `<name>M<number>L`:
|
||||
- same as above, except move by line. For simplicity, assumes that you won't hit a buffer boundary.
|
||||
|
||||
# Helpful terms and concepts
|
||||
- *degenerate*: the text range encompasses no text. Also, means the start and end endpoints are the same.
|
||||
- *TextUnit*: a heuristic for how much to move by. Possible values include `TextUnit_Character`, `TextUnit_Word`, and `TextUnit_Line`. See https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-uiautomationtextunits for more details.
|
256
tools/TestTableWriter/UiaTests.csv
Normal file
256
tools/TestTableWriter/UiaTests.csv
Normal file
|
@ -0,0 +1,256 @@
|
|||
Degenerate,Position,TextUnit,MoveAmount,Start,End,Result_MoveAmount,Result_Start,Result_End,Skip
|
||||
TRUE,1,TextUnit_Character,-5,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Character,-1,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Character,0,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Character,1,origin,origin,1,originP1C,originP1C,FALSE
|
||||
TRUE,1,TextUnit_Character,5,origin,origin,5,originP5C,originP5C,FALSE
|
||||
FALSE,1,TextUnit_Character,-5,origin,originP1C,0,origin,originP1C,FALSE
|
||||
FALSE,1,TextUnit_Character,-1,origin,originP1C,0,origin,originP1C,FALSE
|
||||
FALSE,1,TextUnit_Character,0,origin,originP1C,0,origin,originP1C,FALSE
|
||||
FALSE,1,TextUnit_Character,1,origin,originP1C,1,originP1C,originP2C,FALSE
|
||||
FALSE,1,TextUnit_Character,5,origin,originP1C,5,originP5C,originP6C,FALSE
|
||||
TRUE,2,TextUnit_Character,-5,midTop,midTop,-5,midTopM5C,midTopM5C,FALSE
|
||||
TRUE,2,TextUnit_Character,-1,midTop,midTop,-1,midTopM1C,midTopM1C,FALSE
|
||||
TRUE,2,TextUnit_Character,0,midTop,midTop,0,midTop,midTop,FALSE
|
||||
TRUE,2,TextUnit_Character,1,midTop,midTop,1,midTopP1C,midTopP1C,FALSE
|
||||
TRUE,2,TextUnit_Character,5,midTop,midTop,5,midTopP5C,midTopP5C,FALSE
|
||||
FALSE,2,TextUnit_Character,-5,midTop,midTopP1C,-5,midTopM5C,midTopM4C,FALSE
|
||||
FALSE,2,TextUnit_Character,-1,midTop,midTopP1C,-1,midTopM1C,midTop,FALSE
|
||||
FALSE,2,TextUnit_Character,0,midTop,midTopP1C,0,midTop,midTopP1C,FALSE
|
||||
FALSE,2,TextUnit_Character,1,midTop,midTopP1C,1,midTopP1C,midTopP2C,FALSE
|
||||
FALSE,2,TextUnit_Character,5,midTop,midTopP1C,5,midTopP5C,midTopP6C,FALSE
|
||||
TRUE,3,TextUnit_Character,-5,midHistory,midHistory,-5,midHistoryM5C,midHistoryM5C,FALSE
|
||||
TRUE,3,TextUnit_Character,-1,midHistory,midHistory,-1,midHistoryM1C,midHistoryM1C,FALSE
|
||||
TRUE,3,TextUnit_Character,0,midHistory,midHistory,0,midHistory,midHistory,FALSE
|
||||
TRUE,3,TextUnit_Character,1,midHistory,midHistory,1,midHistoryP1C,midHistoryP1C,FALSE
|
||||
TRUE,3,TextUnit_Character,5,midHistory,midHistory,5,midHistoryP5C,midHistoryP5C,FALSE
|
||||
FALSE,3,TextUnit_Character,-5,midHistory,midHistoryP1C,-5,midHistoryM5C,midHistoryM4C,FALSE
|
||||
FALSE,3,TextUnit_Character,-1,midHistory,midHistoryP1C,-1,midHistoryM1C,midHistory,FALSE
|
||||
FALSE,3,TextUnit_Character,0,midHistory,midHistoryP1C,0,midHistory,midHistoryP1C,FALSE
|
||||
FALSE,3,TextUnit_Character,1,midHistory,midHistoryP1C,1,midHistoryP1C,midHistoryP2C,FALSE
|
||||
FALSE,3,TextUnit_Character,5,midHistory,midHistoryP1C,5,midHistoryP5C,midHistoryP6C,FALSE
|
||||
TRUE,1,TextUnit_Line,-5,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Line,-1,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Line,0,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Line,1,origin,origin,1,originP1L,originP1L,FALSE
|
||||
TRUE,1,TextUnit_Line,5,origin,origin,5,originP5L,originP5L,FALSE
|
||||
FALSE,1,TextUnit_Line,-5,origin,originP1C,0,origin,originP1L,TRUE
|
||||
FALSE,1,TextUnit_Line,-1,origin,originP1C,0,origin,originP1L,TRUE
|
||||
FALSE,1,TextUnit_Line,0,origin,originP1C,0,origin,originP1L,TRUE
|
||||
FALSE,1,TextUnit_Line,1,origin,originP1C,1,originP1L,originP2L,FALSE
|
||||
FALSE,1,TextUnit_Line,5,origin,originP1C,5,originP5L,originP6L,FALSE
|
||||
TRUE,2,TextUnit_Line,-5,midTop,midTop,-1,origin,origin,TRUE
|
||||
TRUE,2,TextUnit_Line,-1,midTop,midTop,-1,origin,origin,TRUE
|
||||
TRUE,2,TextUnit_Line,0,midTop,midTop,0,midTop,midTop,FALSE
|
||||
TRUE,2,TextUnit_Line,1,midTop,midTop,1,midTopP1L,midTopP1L,FALSE
|
||||
TRUE,2,TextUnit_Line,5,midTop,midTop,5,midTopP5L,midTopP5L,FALSE
|
||||
FALSE,2,TextUnit_Line,-5,midTop,midTopP1C,0,origin,originP1L,TRUE
|
||||
FALSE,2,TextUnit_Line,-1,midTop,midTopP1C,0,origin,originP1L,TRUE
|
||||
FALSE,2,TextUnit_Line,0,midTop,midTopP1C,0,origin,originP1L,TRUE
|
||||
FALSE,2,TextUnit_Line,1,midTop,midTopP1C,1,originP1L,originP2L,FALSE
|
||||
FALSE,2,TextUnit_Line,5,midTop,midTopP1C,5,originP5L,originP6L,FALSE
|
||||
TRUE,3,TextUnit_Line,-5,midHistory,midHistory,-5,midHistoryM4L,midHistoryM4L,FALSE
|
||||
TRUE,3,TextUnit_Line,-1,midHistory,midHistory,-1,midHistoryLeft,midHistoryLeft,FALSE
|
||||
TRUE,3,TextUnit_Line,0,midHistory,midHistory,0,midHistory,midHistory,FALSE
|
||||
TRUE,3,TextUnit_Line,1,midHistory,midHistory,1,midHistoryP1L,midHistoryP1L,FALSE
|
||||
TRUE,3,TextUnit_Line,5,midHistory,midHistory,5,midHistoryP5L,midHistoryP5L,FALSE
|
||||
FALSE,3,TextUnit_Line,-5,midHistory,midHistoryP1C,-5,midHistoryM5L,midHistoryM4L,TRUE
|
||||
FALSE,3,TextUnit_Line,-1,midHistory,midHistoryP1C,-1,midHistoryM1L,midHistoryLeft,TRUE
|
||||
FALSE,3,TextUnit_Line,0,midHistory,midHistoryP1C,0,midHistoryLeft,midHistoryP1L,TRUE
|
||||
FALSE,3,TextUnit_Line,1,midHistory,midHistoryP1C,1,midHistoryP1L,midHistoryP2L,FALSE
|
||||
FALSE,3,TextUnit_Line,5,midHistory,midHistoryP1C,5,midHistoryP5L,midHistoryP6L,FALSE
|
||||
TRUE,1,TextUnit_Document,-5,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Document,-1,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Document,0,origin,origin,0,origin,origin,FALSE
|
||||
TRUE,1,TextUnit_Document,1,origin,origin,1,docEnd,docEnd,TRUE
|
||||
TRUE,1,TextUnit_Document,5,origin,origin,1,docEnd,docEnd,TRUE
|
||||
FALSE,1,TextUnit_Document,-5,origin,originP1C,0,origin,docEnd,TRUE
|
||||
FALSE,1,TextUnit_Document,-1,origin,originP1C,0,origin,docEnd,TRUE
|
||||
FALSE,1,TextUnit_Document,0,origin,originP1C,0,origin,docEnd,TRUE
|
||||
FALSE,1,TextUnit_Document,1,origin,originP1C,0,origin,docEnd,TRUE
|
||||
FALSE,1,TextUnit_Document,5,origin,originP1C,0,origin,docEnd,TRUE
|
||||
TRUE,2,TextUnit_Document,-5,midTop,midTop,-1,origin,origin,FALSE
|
||||
TRUE,2,TextUnit_Document,-1,midTop,midTop,-1,origin,origin,FALSE
|
||||
TRUE,2,TextUnit_Document,0,midTop,midTop,0,midTop,midTop,FALSE
|
||||
TRUE,2,TextUnit_Document,1,midTop,midTop,1,bufferEnd,bufferEnd,TRUE
|
||||
TRUE,2,TextUnit_Document,5,midTop,midTop,1,bufferEnd,bufferEnd,TRUE
|
||||
FALSE,2,TextUnit_Document,-5,midTop,midTopP1C,0,origin,bufferEnd,TRUE
|
||||
FALSE,2,TextUnit_Document,-1,midTop,midTopP1C,0,origin,bufferEnd,TRUE
|
||||
FALSE,2,TextUnit_Document,0,midTop,midTopP1C,0,origin,bufferEnd,TRUE
|
||||
FALSE,2,TextUnit_Document,1,midTop,midTopP1C,0,origin,bufferEnd,TRUE
|
||||
FALSE,2,TextUnit_Document,5,midTop,midTopP1C,0,origin,bufferEnd,TRUE
|
||||
TRUE,3,TextUnit_Document,-5,midHistory,midHistory,-1,origin,origin,FALSE
|
||||
TRUE,3,TextUnit_Document,-1,midHistory,midHistory,-1,origin,origin,FALSE
|
||||
TRUE,3,TextUnit_Document,0,midHistory,midHistory,0,midHistory,midHistory,FALSE
|
||||
TRUE,3,TextUnit_Document,1,midHistory,midHistory,1,endExclusive,endExclusive,TRUE
|
||||
TRUE,3,TextUnit_Document,5,midHistory,midHistory,1,endExclusive,endExclusive,TRUE
|
||||
FALSE,3,TextUnit_Document,-5,midHistory,midHistoryP1C,0,origin,endExclusive,TRUE
|
||||
FALSE,3,TextUnit_Document,-1,midHistory,midHistoryP1C,0,origin,endExclusive,TRUE
|
||||
FALSE,3,TextUnit_Document,0,midHistory,midHistoryP1C,0,origin,endExclusive,TRUE
|
||||
FALSE,3,TextUnit_Document,1,midHistory,midHistoryP1C,0,origin,endExclusive,TRUE
|
||||
FALSE,3,TextUnit_Document,5,midHistory,midHistoryP1C,0,origin,endExclusive,TRUE
|
||||
TRUE,8,TextUnit_Character,-5,bufferEnd,bufferEnd,-5,bufferEndM5C,bufferEndM5C,FALSE
|
||||
TRUE,8,TextUnit_Character,-1,bufferEnd,bufferEnd,-1,bufferEndM1C,bufferEndM1C,FALSE
|
||||
TRUE,8,TextUnit_Character,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE
|
||||
TRUE,8,TextUnit_Character,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
TRUE,8,TextUnit_Character,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Character,-5,bufferEnd,endExclusive,-5,bufferEndM5C,bufferEndM4C,FALSE
|
||||
FALSE,8,TextUnit_Character,-1,bufferEnd,endExclusive,-1,bufferEndM1C,bufferEnd,FALSE
|
||||
FALSE,8,TextUnit_Character,0,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE
|
||||
FALSE,8,TextUnit_Character,1,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE
|
||||
FALSE,8,TextUnit_Character,5,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE
|
||||
TRUE,8,TextUnit_Line,-5,bufferEnd,bufferEnd,-5,bufferEndM4L,bufferEndM4L,FALSE
|
||||
TRUE,8,TextUnit_Line,-1,bufferEnd,bufferEnd,-1,bufferEndLeft,bufferEndLeft,FALSE
|
||||
TRUE,8,TextUnit_Line,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE
|
||||
TRUE,8,TextUnit_Line,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
TRUE,8,TextUnit_Line,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Line,-5,bufferEnd,endExclusive,-5,bufferEndM5L,bufferEndM4L,TRUE
|
||||
FALSE,8,TextUnit_Line,-1,bufferEnd,endExclusive,-1,bufferEndM1L,bufferEndLeft,TRUE
|
||||
FALSE,8,TextUnit_Line,0,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Line,1,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Line,5,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE
|
||||
TRUE,8,TextUnit_Document,-5,bufferEnd,bufferEnd,-1,origin,origin,FALSE
|
||||
TRUE,8,TextUnit_Document,-1,bufferEnd,bufferEnd,-1,origin,origin,FALSE
|
||||
TRUE,8,TextUnit_Document,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE
|
||||
TRUE,8,TextUnit_Document,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
TRUE,8,TextUnit_Document,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Document,-5,bufferEnd,endExclusive,0,origin,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Document,-1,bufferEnd,endExclusive,0,origin,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Document,0,bufferEnd,endExclusive,0,origin,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Document,1,bufferEnd,endExclusive,0,origin,endExclusive,TRUE
|
||||
FALSE,8,TextUnit_Document,5,bufferEnd,endExclusive,0,origin,endExclusive,TRUE
|
||||
TRUE,9,TextUnit_Character,-5,endExclusive,endExclusive,-5,bufferEndM4C,bufferEndM4C,FALSE
|
||||
TRUE,9,TextUnit_Character,-1,endExclusive,endExclusive,-1,bufferEnd,bufferEnd,FALSE
|
||||
TRUE,9,TextUnit_Character,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Character,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Character,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Line,-5,endExclusive,endExclusive,-5,bufferEndM4L,bufferEndM4L,FALSE
|
||||
TRUE,9,TextUnit_Line,-1,endExclusive,endExclusive,-1,bufferEndLeft,bufferEndLeft,FALSE
|
||||
TRUE,9,TextUnit_Line,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Line,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Line,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Document,-5,endExclusive,endExclusive,-1,origin,origin,FALSE
|
||||
TRUE,9,TextUnit_Document,-1,endExclusive,endExclusive,-1,origin,origin,FALSE
|
||||
TRUE,9,TextUnit_Document,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Document,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,9,TextUnit_Document,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE
|
||||
TRUE,4,TextUnit_Character,-5,midDocEnd,midDocEnd,-5,midDocEndM5C,midDocEndM5C,TRUE
|
||||
TRUE,4,TextUnit_Character,-1,midDocEnd,midDocEnd,-1,midDocEndM1C,midDocEndM1C,TRUE
|
||||
TRUE,4,TextUnit_Character,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE
|
||||
TRUE,4,TextUnit_Character,1,midDocEnd,midDocEnd,1,midDocEndP1C,midDocEndP1C,TRUE
|
||||
TRUE,4,TextUnit_Character,5,midDocEnd,midDocEnd,5,midDocEndP5C,midDocEndP5C,TRUE
|
||||
FALSE,4,TextUnit_Character,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5C,midDocEndM4C,TRUE
|
||||
FALSE,4,TextUnit_Character,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1C,midDocEnd,TRUE
|
||||
FALSE,4,TextUnit_Character,0,midDocEnd,midDocEndP1C,0,midDocEnd,midDocEndP1C,TRUE
|
||||
FALSE,4,TextUnit_Character,1,midDocEnd,midDocEndP1C,1,midDocEndP1C,midDocEndP2C,TRUE
|
||||
FALSE,4,TextUnit_Character,5,midDocEnd,midDocEndP1C,5,midDocEndP5C,midDocEndP6C,TRUE
|
||||
TRUE,4,TextUnit_Line,-5,midDocEnd,midDocEnd,-5,midDocEndM4L,midDocEndM4L,TRUE
|
||||
TRUE,4,TextUnit_Line,-1,midDocEnd,midDocEnd,-1,midDocEndLeft,midDocEndLeft,TRUE
|
||||
TRUE,4,TextUnit_Line,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE
|
||||
TRUE,4,TextUnit_Line,1,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE
|
||||
TRUE,4,TextUnit_Line,5,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Line,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5L,midDocEndM4L,TRUE
|
||||
FALSE,4,TextUnit_Line,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1L,midDocEndLeft,TRUE
|
||||
FALSE,4,TextUnit_Line,0,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Line,1,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Line,5,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE
|
||||
TRUE,4,TextUnit_Document,-5,midDocEnd,midDocEnd,-1,origin,origin,TRUE
|
||||
TRUE,4,TextUnit_Document,-1,midDocEnd,midDocEnd,-1,origin,origin,TRUE
|
||||
TRUE,4,TextUnit_Document,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE
|
||||
TRUE,4,TextUnit_Document,1,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE
|
||||
TRUE,4,TextUnit_Document,5,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Document,-5,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Document,-1,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Document,0,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Document,1,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE
|
||||
FALSE,4,TextUnit_Document,5,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Character,-5,lastCharPos,lastCharPos,-5,lastCharPosM5C,lastCharPosM5C,TRUE
|
||||
TRUE,5,TextUnit_Character,-1,lastCharPos,lastCharPos,-1,lastCharPosM1C,lastCharPosM1C,TRUE
|
||||
TRUE,5,TextUnit_Character,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE
|
||||
TRUE,5,TextUnit_Character,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Character,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Character,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5C,lastCharPosM4C,TRUE
|
||||
FALSE,5,TextUnit_Character,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1C,lastCharPos,TRUE
|
||||
FALSE,5,TextUnit_Character,0,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Character,1,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Character,5,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Line,-5,lastCharPos,lastCharPos,-5,lastCharPosM4L,lastCharPosM4L,TRUE
|
||||
TRUE,5,TextUnit_Line,-1,lastCharPos,lastCharPos,-1,lastCharPosLeft,lastCharPosLeft,TRUE
|
||||
TRUE,5,TextUnit_Line,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE
|
||||
TRUE,5,TextUnit_Line,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Line,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Line,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5L,lastCharPosM4L,TRUE
|
||||
FALSE,5,TextUnit_Line,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1L,lastCharPosLeft,TRUE
|
||||
FALSE,5,TextUnit_Line,0,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Line,1,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Line,5,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Document,-5,lastCharPos,lastCharPos,-1,origin,origin,TRUE
|
||||
TRUE,5,TextUnit_Document,-1,lastCharPos,lastCharPos,-1,origin,origin,TRUE
|
||||
TRUE,5,TextUnit_Document,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE
|
||||
TRUE,5,TextUnit_Document,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
TRUE,5,TextUnit_Document,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Document,-5,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Document,-1,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Document,0,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Document,1,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE
|
||||
FALSE,5,TextUnit_Document,5,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Character,-5,docEnd,docEnd,-5,docEndM5C,docEndM5C,TRUE
|
||||
TRUE,6,TextUnit_Character,-1,docEnd,docEnd,-1,docEndM1C,docEndM1C,TRUE
|
||||
TRUE,6,TextUnit_Character,0,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Character,1,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Character,5,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Character,-5,docEnd,docEndP1C,-5,docEndM5C,docEndM5C,TRUE
|
||||
FALSE,6,TextUnit_Character,-1,docEnd,docEndP1C,-1,docEndM1C,docEndM1C,TRUE
|
||||
FALSE,6,TextUnit_Character,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Character,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Character,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Line,-5,docEnd,docEnd,-5,docEndM4L,docEndM4L,TRUE
|
||||
TRUE,6,TextUnit_Line,-1,docEnd,docEnd,-1,docEndLeft,docEndLeft,TRUE
|
||||
TRUE,6,TextUnit_Line,0,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Line,1,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Line,5,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Line,-5,docEnd,docEndP1C,-5,docEndM4L,docEndM4L,TRUE
|
||||
FALSE,6,TextUnit_Line,-1,docEnd,docEndP1C,-1,docEndLeft,docEndLeft,TRUE
|
||||
FALSE,6,TextUnit_Line,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Line,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Line,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Document,-5,docEnd,docEnd,-1,origin,origin,TRUE
|
||||
TRUE,6,TextUnit_Document,-1,docEnd,docEnd,-1,origin,origin,TRUE
|
||||
TRUE,6,TextUnit_Document,0,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Document,1,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
TRUE,6,TextUnit_Document,5,docEnd,docEnd,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Document,-5,docEnd,docEndP1C,-1,origin,origin,TRUE
|
||||
FALSE,6,TextUnit_Document,-1,docEnd,docEndP1C,-1,origin,origin,TRUE
|
||||
FALSE,6,TextUnit_Document,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Document,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,6,TextUnit_Document,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpace,-5,docEndM5C,docEndM5C,TRUE
|
||||
TRUE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpace,-1,docEndM1C,docEndM1C,TRUE
|
||||
TRUE,7,TextUnit_Character,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Character,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Character,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM5C,docEndM5C,TRUE
|
||||
FALSE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndM1C,docEndM1C,TRUE
|
||||
FALSE,7,TextUnit_Character,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Character,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Character,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpace,-5,docEndM4L,docEndM4L,TRUE
|
||||
TRUE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpace,-1,docEndLeft,docEndLeft,TRUE
|
||||
TRUE,7,TextUnit_Line,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Line,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Line,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM4L,docEndM4L,TRUE
|
||||
FALSE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndLeft,docEndLeft,TRUE
|
||||
FALSE,7,TextUnit_Line,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Line,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Line,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpace,-1,origin,origin,TRUE
|
||||
TRUE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpace,-1,origin,origin,TRUE
|
||||
TRUE,7,TextUnit_Document,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Document,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
TRUE,7,TextUnit_Document,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,TRUE
|
||||
FALSE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,TRUE
|
||||
FALSE,7,TextUnit_Document,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Document,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
||||
FALSE,7,TextUnit_Document,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE
|
|
Loading…
Reference in a new issue