The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. struct AccessibilityTextHelpersTest : public UnitTest
  21. {
  22. AccessibilityTextHelpersTest()
  23. : UnitTest ("AccessibilityTextHelpers", UnitTestCategories::gui) {}
  24. void runTest() override
  25. {
  26. using ATH = AccessibilityTextHelpers;
  27. beginTest ("Android find word end");
  28. {
  29. const auto testMultiple = [this] (String str,
  30. int start,
  31. const std::vector<int>& collection)
  32. {
  33. auto it = collection.begin();
  34. for (const auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
  35. {
  36. for (const auto includeBoundary : { ATH::IncludeThisBoundary::no, ATH::IncludeThisBoundary::yes })
  37. {
  38. for (const auto includeWhitespace : { ATH::IncludeWhitespaceAfterWords::no, ATH::IncludeWhitespaceAfterWords::yes })
  39. {
  40. const auto actual = ATH::findNextWordEndOffset (str.begin(), str.end(), str.begin() + start, direction, includeBoundary, includeWhitespace);
  41. const auto expected = *it++;
  42. expect (expected == actual);
  43. }
  44. }
  45. }
  46. };
  47. // Character Indices 0 3 56 13 50 51
  48. // | | || | | |
  49. const auto string = String ("hello world \r\n with some spaces in this sentence ") + String (CharPointer_UTF8 ("\xe2\x88\xae E\xe2\x8b\x85""da = Q"));
  50. // Direction forwards forwards forwards forwards backwards backwards backwards backwards
  51. // IncludeBoundary no no yes yes no no yes yes
  52. // IncludeWhitespace no yes no yes no yes no yes
  53. testMultiple (string, 0, { 5, 6, 5, 0, 0, 0, 0, 0 });
  54. testMultiple (string, 3, { 2, 3, 2, 3, -3, -3, -3, -3 });
  55. testMultiple (string, 5, { 6, 1, 0, 1, -5, -5, -5, 0 });
  56. testMultiple (string, 6, { 5, 9, 5, 0, -6, -1, 0, -1 });
  57. testMultiple (string, 13, { 6, 2, 6, 2, -7, -2, -7, -2 });
  58. testMultiple (string, 50, { 1, 2, 1, 0, -9, -1, 0, -1 });
  59. testMultiple (string, 51, { 5, 1, 0, 1, -1, -2, -1, 0 });
  60. testMultiple (" a b ", 0, { 3, 2, 0, 2, 0, 0, 0, 0 });
  61. testMultiple (" a b ", 1, { 2, 1, 2, 1, -1, -1, -1, -1 });
  62. }
  63. beginTest ("Android text range adjustment");
  64. {
  65. const auto testMultiple = [this] (String str,
  66. Range<int> initial,
  67. auto boundary,
  68. const std::vector<Range<int>>& collection)
  69. {
  70. auto it = collection.begin();
  71. for (auto extend : { ATH::ExtendSelection::no, ATH::ExtendSelection::yes })
  72. {
  73. for (auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
  74. {
  75. for (auto insert : { CursorPosition::begin, CursorPosition::end })
  76. {
  77. const MockAccessibilityTextInterface mock { str, initial, insert };
  78. const auto actual = ATH::findNewSelectionRangeAndroid (mock, boundary, extend, direction);
  79. const auto expected = *it++;
  80. expect (expected == actual);
  81. }
  82. }
  83. }
  84. };
  85. // Extend no no no no yes yes yes yes
  86. // Direction forwards forwards backwards backwards forwards forwards backwards backwards
  87. // Insert begin end begin end begin end begin end
  88. testMultiple ("hello world", { 5, 5 }, ATH::BoundaryType::character, { { 6, 6 }, { 6, 6 }, { 4, 4 }, { 4, 4 }, { 5, 6 }, { 5, 6 }, { 4, 5 }, { 4, 5 } });
  89. testMultiple ("hello world", { 0, 0 }, ATH::BoundaryType::character, { { 1, 1 }, { 1, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 }, { 0, 1 }, { 0, 0 }, { 0, 0 } });
  90. testMultiple ("hello world", { 11, 11 }, ATH::BoundaryType::character, { { 11, 11 }, { 11, 11 }, { 10, 10 }, { 10, 10 }, { 11, 11 }, { 11, 11 }, { 10, 11 }, { 10, 11 } });
  91. testMultiple ("hello world", { 4, 5 }, ATH::BoundaryType::character, { { 5, 5 }, { 6, 6 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 4, 6 }, { 3, 5 }, { 4, 4 } });
  92. testMultiple ("hello world", { 0, 1 }, ATH::BoundaryType::character, { { 1, 1 }, { 2, 2 }, { 0, 0 }, { 0, 0 }, { 1, 1 }, { 0, 2 }, { 0, 1 }, { 0, 0 } });
  93. testMultiple ("hello world", { 10, 11 }, ATH::BoundaryType::character, { { 11, 11 }, { 11, 11 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 10, 11 }, { 9, 11 }, { 10, 10 } });
  94. testMultiple ("foo bar baz", { 0, 0 }, ATH::BoundaryType::word, { { 3, 3 }, { 3, 3 }, { 0, 0 }, { 0, 0 }, { 0, 3 }, { 0, 3 }, { 0, 0 }, { 0, 0 } });
  95. testMultiple ("foo bar baz", { 1, 6 }, ATH::BoundaryType::word, { { 3, 3 }, { 8, 8 }, { 0, 0 }, { 5, 5 }, { 3, 6 }, { 1, 8 }, { 0, 6 }, { 1, 5 } });
  96. testMultiple ("foo bar baz", { 3, 3 }, ATH::BoundaryType::word, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 3, 8 }, { 3, 8 }, { 0, 3 }, { 0, 3 } });
  97. testMultiple ("foo bar baz", { 3, 5 }, ATH::BoundaryType::word, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 5, 8 }, { 3, 8 }, { 0, 5 }, { 0, 3 } });
  98. testMultiple ("foo bar\n\n\na b\nc d e", { 0, 0 }, ATH::BoundaryType::line, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 0, 8 }, { 0, 8 }, { 0, 0 }, { 0, 0 } });
  99. testMultiple ("foo bar\n\n\na b\nc d e", { 7, 7 }, ATH::BoundaryType::line, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 7, 8 }, { 7, 8 }, { 0, 7 }, { 0, 7 } });
  100. testMultiple ("foo bar\n\n\na b\nc d e", { 8, 8 }, ATH::BoundaryType::line, { { 9, 9 }, { 9, 9 }, { 0, 0 }, { 0, 0 }, { 8, 9 }, { 8, 9 }, { 0, 8 }, { 0, 8 } });
  101. testMultiple ("foo bar\r\na b\r\nxyz", { 0, 0 }, ATH::BoundaryType::line, { { 9, 9 }, { 9, 9 }, { 0, 0 }, { 0, 0 }, { 0, 9 }, { 0, 9 }, { 0, 0 }, { 0, 0 } });
  102. testMultiple ("foo bar\r\na b\r\nxyz", { 10, 10 }, ATH::BoundaryType::line, { { 14, 14 }, { 14, 14 }, { 9, 9 }, { 9, 9 }, { 10, 14 }, { 10, 14 }, { 9, 10 }, { 9, 10 } });
  103. }
  104. }
  105. enum class CursorPosition { begin, end };
  106. class MockAccessibilityTextInterface : public AccessibilityTextInterface
  107. {
  108. public:
  109. MockAccessibilityTextInterface (String stringIn, Range<int> selectionIn, CursorPosition insertIn)
  110. : string (stringIn), selection (selectionIn), insert (insertIn) {}
  111. bool isDisplayingProtectedText() const override { return false; }
  112. bool isReadOnly() const override { return false; }
  113. int getTotalNumCharacters() const override { return string.length(); }
  114. Range<int> getSelection() const override { return selection; }
  115. int getTextInsertionOffset() const override { return insert == CursorPosition::begin ? selection.getStart() : selection.getEnd(); }
  116. String getText (Range<int> range) const override { return string.substring (range.getStart(), range.getEnd()); }
  117. RectangleList<int> getTextBounds (Range<int>) const override { return {}; }
  118. int getOffsetAtPoint (Point<int>) const override { return 0; }
  119. void setSelection (Range<int> newRange) override { selection = newRange; }
  120. void setText (const String& newText) override { string = newText; }
  121. private:
  122. String string;
  123. Range<int> selection;
  124. CursorPosition insert;
  125. };
  126. };
  127. static AccessibilityTextHelpersTest accessibilityTextHelpersTest;
  128. } // namespace juce