mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-06-23 09:30:53 +00:00
update InputLogicTest
This commit is contained in:
parent
9bd6c2403e
commit
52a049bee6
1 changed files with 94 additions and 25 deletions
|
@ -8,10 +8,10 @@ import android.text.InputType
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.inputmethod.*
|
import android.view.inputmethod.*
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.test.runner.AndroidJUnit4
|
|
||||||
import org.dslul.openboard.inputmethod.event.Event
|
import org.dslul.openboard.inputmethod.event.Event
|
||||||
import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher
|
import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher
|
||||||
import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView
|
import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView
|
||||||
|
import org.dslul.openboard.inputmethod.latin.common.Constants
|
||||||
import org.dslul.openboard.inputmethod.latin.common.StringUtils
|
import org.dslul.openboard.inputmethod.latin.common.StringUtils
|
||||||
import org.dslul.openboard.inputmethod.latin.inputlogic.InputLogic
|
import org.dslul.openboard.inputmethod.latin.inputlogic.InputLogic
|
||||||
import org.dslul.openboard.inputmethod.latin.settings.Settings
|
import org.dslul.openboard.inputmethod.latin.settings.Settings
|
||||||
|
@ -23,6 +23,7 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
import org.robolectric.Robolectric
|
import org.robolectric.Robolectric
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.robolectric.annotation.Implementation
|
import org.robolectric.annotation.Implementation
|
||||||
import org.robolectric.annotation.Implements
|
import org.robolectric.annotation.Implements
|
||||||
|
@ -30,7 +31,7 @@ import org.robolectric.shadows.ShadowLog
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(shadows = [
|
@Config(shadows = [
|
||||||
ShadowLocaleManagerCompat::class,
|
ShadowLocaleManagerCompat::class,
|
||||||
ShadowInputMethodManager2::class,
|
ShadowInputMethodManager2::class,
|
||||||
|
@ -69,11 +70,20 @@ class InputLogicTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun delete() {
|
@Test fun delete() {
|
||||||
|
reset()
|
||||||
|
setText("hello there ")
|
||||||
|
functionalKeyPress(Constants.CODE_DELETE)
|
||||||
|
assertEquals("hello there", text)
|
||||||
|
assertEquals("there", composingText)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun deleteInWeirdEditor() { // todo: try reproducing the thing requiring to fix incorrect length
|
@Test fun deleteInsideWord() {
|
||||||
|
reset()
|
||||||
|
setText("hello you there")
|
||||||
|
setCursorPosition(8) // after o in you
|
||||||
|
functionalKeyPress(Constants.CODE_DELETE)
|
||||||
|
assertEquals("hello yu there", text)
|
||||||
|
assertEquals("", composingText) // todo: do we really want an empty composing text in this case?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun insertLetterIntoWord() {
|
@Test fun insertLetterIntoWord() {
|
||||||
|
@ -85,6 +95,7 @@ class InputLogicTest {
|
||||||
assertEquals("helilo", getText())
|
assertEquals("helilo", getText())
|
||||||
assertEquals(4, getCursorPosition())
|
assertEquals(4, getCursorPosition())
|
||||||
assertEquals(4, cursor)
|
assertEquals(4, cursor)
|
||||||
|
assertEquals("", composingText)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun insertLetterIntoWordWithWeirdEditor() {
|
@Test fun insertLetterIntoWordWithWeirdEditor() {
|
||||||
|
@ -123,10 +134,37 @@ class InputLogicTest {
|
||||||
assertEquals(4, cursor)
|
assertEquals(4, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun setAutospace() {
|
// todo: try the same if there is text afterwards (not touching)
|
||||||
println(settingsValues.mAutospaceAfterPunctuationEnabled)
|
@Test fun autospace() {
|
||||||
setAutospaceAfterPunctuation(true)
|
reset()
|
||||||
println(settingsValues.mAutospaceAfterPunctuationEnabled)
|
setText("hello")
|
||||||
|
input('.'.code)
|
||||||
|
input('a'.code)
|
||||||
|
assertEquals("hello.a", textBeforeCursor)
|
||||||
|
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
|
||||||
|
assert(settingsValues.mAutospaceAfterPunctuationEnabled)
|
||||||
|
setText("hello")
|
||||||
|
input('.'.code)
|
||||||
|
input('a'.code)
|
||||||
|
assertEquals("hello. a", textBeforeCursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun autospaceButWithTextAfter() {
|
||||||
|
reset()
|
||||||
|
setText("hello there")
|
||||||
|
setCursorPosition(5) // after hello
|
||||||
|
input('.'.code)
|
||||||
|
input('a'.code)
|
||||||
|
assertEquals("hello.a", textBeforeCursor)
|
||||||
|
assertEquals("hello.a there", text)
|
||||||
|
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
|
||||||
|
assert(settingsValues.mAutospaceAfterPunctuationEnabled)
|
||||||
|
setText("hello there")
|
||||||
|
setCursorPosition(5) // after hello
|
||||||
|
input('.'.code)
|
||||||
|
input('a'.code)
|
||||||
|
assertEquals("hello. a", textBeforeCursor)
|
||||||
|
assertEquals("hello. a there", text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------- helper functions ---------
|
// ------- helper functions ---------
|
||||||
|
@ -162,12 +200,19 @@ class InputLogicTest {
|
||||||
latinIME.onEvent(Event.createEventForCodePointFromUnknownSource(codePoint))
|
latinIME.onEvent(Event.createEventForCodePointFromUnknownSource(codePoint))
|
||||||
handleMessages()
|
handleMessages()
|
||||||
|
|
||||||
|
if (!settingsValues.mAutospaceAfterPunctuationEnabled)
|
||||||
assertEquals(oldBefore + insert, textBeforeCursor)
|
assertEquals(oldBefore + insert, textBeforeCursor)
|
||||||
assertEquals(oldAfter, textAfterCursor)
|
assertEquals(oldAfter, textAfterCursor)
|
||||||
assertEquals(textBeforeCursor + textAfterCursor, getText())
|
assertEquals(textBeforeCursor + textAfterCursor, getText())
|
||||||
checkConnectionConsistency()
|
checkConnectionConsistency()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun functionalKeyPress(keyCode: Int) {
|
||||||
|
latinIME.onEvent(Event.createSoftwareKeypressEvent(Event.NOT_A_CODE_POINT, keyCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false))
|
||||||
|
handleMessages()
|
||||||
|
checkConnectionConsistency()
|
||||||
|
}
|
||||||
|
|
||||||
// almost the same as codePoint input, but calls different latinIME function
|
// almost the same as codePoint input, but calls different latinIME function
|
||||||
private fun input(insert: String) {
|
private fun input(insert: String) {
|
||||||
val oldBefore = textBeforeCursor
|
val oldBefore = textBeforeCursor
|
||||||
|
@ -259,8 +304,8 @@ class InputLogicTest {
|
||||||
|
|
||||||
private fun checkConnectionConsistency() {
|
private fun checkConnectionConsistency() {
|
||||||
println("consistency: $selectionStart, ${connection.expectedSelectionStart}, $selectionEnd, ${connection.expectedSelectionEnd}, $textBeforeComposingText, " +
|
println("consistency: $selectionStart, ${connection.expectedSelectionStart}, $selectionEnd, ${connection.expectedSelectionEnd}, $textBeforeComposingText, " +
|
||||||
"$connectionTextBeforeComposingText, $composingText, $connectionComposingText, $textBeforeCursor, ${connection.getTextBeforeCursor(textBeforeCursor.length, 0)}," +
|
"$connectionTextBeforeComposingText, $composingText, $connectionComposingText, $textBeforeCursor, ${connection.getTextBeforeCursor(textBeforeCursor.length, 0)}" +
|
||||||
" $textAfterCursor, ${connection.getTextBeforeCursor(textAfterCursor.length, 0)}")
|
", $textAfterCursor, ${connection.getTextAfterCursor(textAfterCursor.length, 0)}")
|
||||||
assertEquals(selectionStart, connection.expectedSelectionStart)
|
assertEquals(selectionStart, connection.expectedSelectionStart)
|
||||||
assertEquals(selectionEnd, connection.expectedSelectionEnd)
|
assertEquals(selectionEnd, connection.expectedSelectionEnd)
|
||||||
assertEquals(textBeforeComposingText, connectionTextBeforeComposingText)
|
assertEquals(textBeforeComposingText, connectionTextBeforeComposingText)
|
||||||
|
@ -272,13 +317,6 @@ class InputLogicTest {
|
||||||
private fun getText() =
|
private fun getText() =
|
||||||
connection.getTextBeforeCursor(100, 0).toString() + connection.getTextAfterCursor(100, 0)
|
connection.getTextBeforeCursor(100, 0).toString() + connection.getTextAfterCursor(100, 0)
|
||||||
|
|
||||||
// nice, this really reloads the prefs!!
|
|
||||||
private fun setAutospaceAfterPunctuation(enabled: Boolean) {
|
|
||||||
DeviceProtectedUtils.getSharedPreferences(latinIME)
|
|
||||||
.edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, enabled) }
|
|
||||||
assertEquals(enabled, settingsValues.mAutospaceAfterPunctuationEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
// always need to handle messages for proper simulation
|
// always need to handle messages for proper simulation
|
||||||
private fun handleMessages() {
|
private fun handleMessages() {
|
||||||
while (messages.isNotEmpty()) {
|
while (messages.isNotEmpty()) {
|
||||||
|
@ -338,9 +376,10 @@ private val ic = object : InputConnection {
|
||||||
else text.substring(selectionStart, selectionEnd)
|
else text.substring(selectionStart, selectionEnd)
|
||||||
// inserts text at cursor (right?), and sets it as composing text
|
// inserts text at cursor (right?), and sets it as composing text
|
||||||
// this REPLACES currently composing text (even if at a different position)
|
// this REPLACES currently composing text (even if at a different position)
|
||||||
// moves the cursor: positive means relative to composing text, negative means relative to start
|
// moves the cursor: positive means relative to composing text start, negative means relative to start
|
||||||
override fun setComposingText(newText: CharSequence, cursor: Int): Boolean {
|
override fun setComposingText(newText: CharSequence, cursor: Int): Boolean {
|
||||||
// first remove the composing text if necessary
|
println("set composing text $newText, $cursor")
|
||||||
|
// first remove the composing text if any
|
||||||
if (composingStart != -1 && composingEnd != -1)
|
if (composingStart != -1 && composingEnd != -1)
|
||||||
text = textBeforeComposingText + text.substring(composingEnd)
|
text = textBeforeComposingText + text.substring(composingEnd)
|
||||||
else // no composing span active, we should remove selected text
|
else // no composing span active, we should remove selected text
|
||||||
|
@ -354,8 +393,11 @@ private val ic = object : InputConnection {
|
||||||
text = text.substring(0, insertStart) + newText + text.substring(insertStart)
|
text = text.substring(0, insertStart) + newText + text.substring(insertStart)
|
||||||
composingStart = insertStart
|
composingStart = insertStart
|
||||||
composingEnd = insertStart + newText.length
|
composingEnd = insertStart + newText.length
|
||||||
selectionStart = if (insertStart > 0) insertStart + cursor
|
// the cursor -1 is not clear in documentation, but
|
||||||
else cursor
|
// "So a value of 1 will always advance you to the position after the full text being inserted"
|
||||||
|
// means that 1 must be composingEnd
|
||||||
|
selectionStart = if (cursor > 0) composingEnd + cursor - 1
|
||||||
|
else -cursor
|
||||||
selectionEnd = selectionStart
|
selectionEnd = selectionStart
|
||||||
// todo: this should call InputMethodManager#updateSelection(View, int, int, int, int)
|
// todo: this should call InputMethodManager#updateSelection(View, int, int, int, int)
|
||||||
// but only after batch edit has ended
|
// but only after batch edit has ended
|
||||||
|
@ -405,9 +447,36 @@ private val ic = object : InputConnection {
|
||||||
// todo: call InputMethodService.onUpdateSelection(int, int, int, int, int, int), but only after batch edit is done!
|
// todo: call InputMethodService.onUpdateSelection(int, int, int, int, int, int), but only after batch edit is done!
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// delete beforeLength before cursor position, and afterLength after cursor position
|
||||||
|
// chars, not codepoints or glyphs
|
||||||
|
// todo: may delete only one half of a surrogate pair, but this should be avoided by RichInputConnection (maybe throw error)
|
||||||
|
override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean {
|
||||||
|
// delete only before or after selection
|
||||||
|
text = textBeforeCursor.substring(0, textBeforeCursor.length - beforeLength) +
|
||||||
|
text.substring(selectionStart, selectionEnd) +
|
||||||
|
textAfterCursor.substring(afterLength)
|
||||||
|
|
||||||
|
// if parts of the composing span are deleted, shorten the span (set end to shorter)
|
||||||
|
if (selectionStart <= composingStart) {
|
||||||
|
composingStart -= beforeLength // is this correct?
|
||||||
|
composingEnd -= beforeLength
|
||||||
|
} else if (selectionStart <= composingEnd) {
|
||||||
|
composingEnd -= beforeLength // is this correct?
|
||||||
|
}
|
||||||
|
if (selectionEnd <= composingStart) {
|
||||||
|
composingStart -= afterLength
|
||||||
|
composingEnd -= afterLength
|
||||||
|
} else if (selectionEnd <= composingEnd) {
|
||||||
|
composingEnd -= afterLength
|
||||||
|
}
|
||||||
|
// update selection
|
||||||
|
selectionStart -= beforeLength
|
||||||
|
selectionEnd -= beforeLength
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// implement only when necessary
|
||||||
override fun getCursorCapsMode(p0: Int): Int = TODO("Not yet implemented")
|
override fun getCursorCapsMode(p0: Int): Int = TODO("Not yet implemented")
|
||||||
override fun getExtractedText(p0: ExtractedTextRequest?, p1: Int): ExtractedText = TODO("Not yet implemented")
|
override fun getExtractedText(p0: ExtractedTextRequest?, p1: Int): ExtractedText = TODO("Not yet implemented")
|
||||||
override fun deleteSurroundingText(p0: Int, p1: Int): Boolean = TODO("Not yet implemented")
|
|
||||||
override fun deleteSurroundingTextInCodePoints(p0: Int, p1: Int): Boolean = TODO("Not yet implemented")
|
override fun deleteSurroundingTextInCodePoints(p0: Int, p1: Int): Boolean = TODO("Not yet implemented")
|
||||||
override fun commitCompletion(p0: CompletionInfo?): Boolean = TODO("Not yet implemented")
|
override fun commitCompletion(p0: CompletionInfo?): Boolean = TODO("Not yet implemented")
|
||||||
override fun commitCorrection(p0: CorrectionInfo?): Boolean = TODO("Not yet implemented")
|
override fun commitCorrection(p0: CorrectionInfo?): Boolean = TODO("Not yet implemented")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue