update tests and readme

This commit is contained in:
Helium314 2023-09-25 07:11:33 +02:00
parent a330e9dd17
commit cf261bf5ef
3 changed files with 68 additions and 48 deletions

View file

@ -28,9 +28,10 @@ Features that may go unnoticed
* Long-press comma to access clipboard view, emoji view, one-handed mode, settings, or switch language * Long-press comma to access clipboard view, emoji view, one-handed mode, settings, or switch language
* emoji view and language switch will disappear if you have the corresponding key enabled * emoji view and language switch will disappear if you have the corresponding key enabled
* for some layouts it's not the comma-key, but the key at the same position (e.g. it's `q` for Dvorak layout) * for some layouts it's not the comma-key, but the key at the same position (e.g. it's `q` for Dvorak layout)
* Press the incognito icon to get the toolbar (probably only hidden if you use _force incognito mode_)
* Sliding key input: swipe from shift to another key to type a single uppercase key * Sliding key input: swipe from shift to another key to type a single uppercase key
* also works for the `?123` key to type a single symbol from the symbols keyboard, and for related keys * also works for the `?123` key to type a single symbol from the symbols keyboard, and for related keys
* Long-press a suggestion to show more suggestions, and a delete button to remove this suggestion * Long-press a suggestion in suggestion strip to show more suggestions, and a delete button to remove this suggestion
* Swipe up from a suggestion to open more suggestions, and release on the suggestion to select it * Swipe up from a suggestion to open more suggestions, and release on the suggestion to select it
* You can add dictionaries by opening them in a file explorer * You can add dictionaries by opening them in a file explorer
* only works with content-uris and not with file-uris, meaning that it may not work with some file explorers * only works with content-uris and not with file-uris, meaning that it may not work with some file explorers

View file

@ -61,7 +61,7 @@ class InputLogicTest {
@Test fun inputCode() { @Test fun inputCode() {
reset() reset()
input('c'.code) input('c')
assertEquals("c", textBeforeCursor) assertEquals("c", textBeforeCursor)
assertEquals("c", getText()) assertEquals("c", getText())
assertEquals("", textAfterCursor) assertEquals("", textAfterCursor)
@ -91,7 +91,7 @@ class InputLogicTest {
reset() reset()
setText("hello") setText("hello")
setCursorPosition(3) // after first l setCursorPosition(3) // after first l
input('i'.code) input('i')
assertEquals("helilo", getWordAtCursor()) assertEquals("helilo", getWordAtCursor())
assertEquals("helilo", getText()) assertEquals("helilo", getText())
assertEquals(4, getCursorPosition()) assertEquals(4, getCursorPosition())
@ -104,7 +104,7 @@ class InputLogicTest {
currentInputType = 180225 // should not change much, but just to be sure currentInputType = 180225 // should not change much, but just to be sure
setText("hello") setText("hello")
setCursorPosition(3, weirdTextField = true) // after first l setCursorPosition(3, weirdTextField = true) // after first l
input('i'.code) input('i')
assertEquals("helilo", getWordAtCursor()) assertEquals("helilo", getWordAtCursor())
assertEquals("helilo", getText()) assertEquals("helilo", getText())
assertEquals(4, getCursorPosition()) assertEquals(4, getCursorPosition())
@ -115,7 +115,7 @@ class InputLogicTest {
reset() reset()
setText("hello my friend") setText("hello my friend")
setCursorPosition(7) // between m and y setCursorPosition(7) // between m and y
input('a'.code) input('a')
assertEquals("may", getWordAtCursor()) assertEquals("may", getWordAtCursor())
assertEquals("hello may friend", getText()) assertEquals("hello may friend", getText())
assertEquals(8, getCursorPosition()) assertEquals(8, getCursorPosition())
@ -127,7 +127,7 @@ class InputLogicTest {
currentScript = ScriptUtils.SCRIPT_HANGUL currentScript = ScriptUtils.SCRIPT_HANGUL
setText("ㅛㅎㄹㅎㅕㅛ") setText("ㅛㅎㄹㅎㅕㅛ")
setCursorPosition(3) setCursorPosition(3)
input('ㄲ'.code) // fails, as expected from the hangul issue when processing the event in onCodeInput input('ㄲ') // fails, as expected from the hangul issue when processing the event in onCodeInput
assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", getWordAtCursor()) assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", getWordAtCursor())
assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", getText()) assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", getText())
assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", textBeforeCursor + textAfterCursor) assertEquals("ㅛㅎㄹㄲㅎㅕㅛ", textBeforeCursor + textAfterCursor)
@ -139,7 +139,7 @@ class InputLogicTest {
reset() reset()
setText("hello") setText("hello")
assertEquals("hello", composingText) assertEquals("hello", composingText)
input('.'.code) input('.')
assertEquals("", composingText) assertEquals("", composingText)
} }
@ -147,13 +147,13 @@ class InputLogicTest {
@Test fun autospace() { @Test fun autospace() {
reset() reset()
setText("hello") setText("hello")
input('.'.code) input('.')
input('a'.code) input('a')
assertEquals("hello.a", textBeforeCursor) assertEquals("hello.a", textBeforeCursor)
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
setText("hello") setText("hello")
input('.'.code) input('.')
input('a'.code) input('a')
assertEquals("hello. a", textBeforeCursor) assertEquals("hello. a", textBeforeCursor)
} }
@ -161,15 +161,15 @@ class InputLogicTest {
reset() reset()
setText("hello there") setText("hello there")
setCursorPosition(5) // after hello setCursorPosition(5) // after hello
input('.'.code) input('.')
input('a'.code) input('a')
assertEquals("hello.a", textBeforeCursor) assertEquals("hello.a", textBeforeCursor)
assertEquals("hello.a there", text) assertEquals("hello.a there", text)
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
setText("hello there") setText("hello there")
setCursorPosition(5) // after hello setCursorPosition(5) // after hello
input('.'.code) input('.')
input('a'.code) input('a')
assertEquals("hello. a", textBeforeCursor) assertEquals("hello. a", textBeforeCursor)
assertEquals("hello. a there", text) assertEquals("hello. a there", text)
} }
@ -177,33 +177,33 @@ class InputLogicTest {
@Test fun urlDetectionThings() { @Test fun urlDetectionThings() {
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
input('.'.code) input('.')
input('.'.code) input('.')
input('.'.code) input('.')
input('h'.code) input('h')
assertEquals("...h", text) assertEquals("...h", text)
assertEquals("h", composingText) assertEquals("h", composingText)
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
input("bla") input("bla")
input('.'.code) input('.')
input('.'.code) input('.')
assertEquals("bla..", text) assertEquals("bla..", text)
assertEquals("", composingText) assertEquals("", composingText)
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
input("bla") input("bla")
input('.'.code) input('.')
input('c'.code) input('c')
assertEquals("bla.c", text) assertEquals("bla.c", text)
assertEquals("bla.c", composingText) assertEquals("bla.c", composingText)
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
input("bla") input("bla")
input('.'.code) input('.')
functionalKeyPress(Constants.CODE_SHIFT) // should remove the phantom space (in addition to normal effect) functionalKeyPress(Constants.CODE_SHIFT) // should remove the phantom space (in addition to normal effect)
input('c'.code) input('c')
assertEquals("bla.c", text) assertEquals("bla.c", text)
assertEquals("bla.c", composingText) assertEquals("bla.c", composingText)
} }
@ -212,10 +212,10 @@ class InputLogicTest {
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
setText("example.co") setText("example.co")
input('m'.code) input('m')
input('.'.code) input('.')
assertEquals("example.com.", composingText) assertEquals("example.com.", composingText)
input(' '.code) input(' ')
assertEquals("example.com", ShadowFacilitator2.lastAddedWord) assertEquals("example.com", ShadowFacilitator2.lastAddedWord)
} }
@ -223,9 +223,9 @@ class InputLogicTest {
reset() reset()
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) } DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
setText("bl") setText("bl")
input('a'.code) input('a')
input('.'.code) input('.')
input('.'.code) input('.')
assertEquals("", composingText) assertEquals("", composingText)
assertEquals("bla..", text) assertEquals("bla..", text)
} }
@ -237,6 +237,18 @@ class InputLogicTest {
assertEquals("s is ", text.substring(3, 8)) assertEquals("s is ", text.substring(3, 8))
} }
@Test fun noComposingForPasswordFields() {
reset()
setInputType(InputType.TYPE_CLASS_TEXT and InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)
input('a')
input('b')
assertEquals("", composingText)
DeviceProtectedUtils.getSharedPreferences(latinIME).edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
input('.')
input('c')
assertEquals("", composingText)
}
// ------- helper functions --------- // ------- helper functions ---------
// should be called before every test, so the same state is guaranteed // should be called before every test, so the same state is guaranteed
@ -258,6 +270,7 @@ class InputLogicTest {
setText("") setText("")
} }
private fun input(char: Char) = input(char.code)
private fun input(codePoint: Int) { private fun input(codePoint: Int) {
val oldBefore = textBeforeCursor val oldBefore = textBeforeCursor
val oldAfter = textAfterCursor val oldAfter = textAfterCursor
@ -373,6 +386,12 @@ class InputLogicTest {
private fun getText() = private fun getText() =
connection.getTextBeforeCursor(100, 0).toString() + (connection.getSelectedText(0) ?: "") + connection.getTextAfterCursor(100, 0) connection.getTextBeforeCursor(100, 0).toString() + (connection.getSelectedText(0) ?: "") + connection.getTextAfterCursor(100, 0)
private fun setInputType(inputType: Int) {
// set text to actually apply input type
currentInputType = inputType
setText(text)
}
// 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()) {

View file

@ -1,7 +1,6 @@
package org.dslul.openboard.inputmethod.latin package org.dslul.openboard.inputmethod.latin
import androidx.core.content.edit import androidx.core.content.edit
import androidx.test.runner.AndroidJUnit4
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo.KIND_FLAG_APPROPRIATE_FOR_AUTO_CORRECTION import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo.KIND_FLAG_APPROPRIATE_FOR_AUTO_CORRECTION
import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo.KIND_WHITELIST import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo.KIND_WHITELIST
@ -15,13 +14,14 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
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
import org.robolectric.shadows.ShadowLog import org.robolectric.shadows.ShadowLog
import java.util.* import java.util.*
@RunWith(AndroidJUnit4::class) @RunWith(RobolectricTestRunner::class)
@Config(shadows = [ @Config(shadows = [
ShadowLocaleManagerCompat::class, ShadowLocaleManagerCompat::class,
ShadowInputMethodManager2::class, ShadowInputMethodManager2::class,
@ -46,7 +46,7 @@ class SuggestTest {
.edit { putBoolean(Settings.PREF_AUTO_CORRECTION, true) } // need to enable, off by default .edit { putBoolean(Settings.PREF_AUTO_CORRECTION, true) } // need to enable, off by default
} }
@Test fun `"on" to "in" if "in" was used before in this context`() { @Test fun `'on' to 'in' if 'in' was used before in this context`() {
val locale = Locale.ENGLISH val locale = Locale.ENGLISH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"on", "on",
@ -60,7 +60,7 @@ class SuggestTest {
// not corrected because first suggestion score is too low // not corrected because first suggestion score is too low
} }
@Test fun `"ill" to "I'll" if "ill" not used before in this context, and I'll has shortcut`() { @Test fun `'ill' to 'I'll' if 'ill' not used before in this context, and I'll has shortcut`() {
val locale = Locale.ENGLISH val locale = Locale.ENGLISH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ill", "ill",
@ -74,7 +74,7 @@ class SuggestTest {
// correction because both empty scores are 0, which should be fine (next check is comparing empty scores) // correction because both empty scores are 0, which should be fine (next check is comparing empty scores)
} }
@Test fun `not "ill" to "I'll" if only "ill" was used before in this context`() { @Test fun `not 'ill' to 'I'll' if only 'ill' was used before in this context`() {
val locale = Locale.ENGLISH val locale = Locale.ENGLISH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ill", "ill",
@ -88,7 +88,7 @@ class SuggestTest {
// not corrected because first empty score not high enough // not corrected because first empty score not high enough
} }
@Test fun `"ill" to "I'll" if both have same ngram score`() { @Test fun `'ill' to 'I'll' if both have same ngram score`() {
val locale = Locale.ENGLISH val locale = Locale.ENGLISH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ill", "ill",
@ -101,7 +101,7 @@ class SuggestTest {
assert(result.last()) // should be corrected assert(result.last()) // should be corrected
} }
@Test fun `no "ill" to "I'll" if "ill" has somewhat better ngram score`() { @Test fun `no 'ill' to 'I'll' if 'ill' has somewhat better ngram score`() {
val locale = Locale.ENGLISH val locale = Locale.ENGLISH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ill", "ill",
@ -114,7 +114,7 @@ class SuggestTest {
assert(!result.last()) // should not be corrected assert(!result.last()) // should not be corrected
} }
@Test fun `no English "I" for Polish "i" when typing in Polish`() { @Test fun `no English 'I' for Polish 'i' when typing in Polish`() {
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"i", "i",
listOf(suggestion("I", Int.MAX_VALUE, Locale.ENGLISH), suggestion("i", 1500000, Locale("pl"))), listOf(suggestion("I", Int.MAX_VALUE, Locale.ENGLISH), suggestion("i", 1500000, Locale("pl"))),
@ -128,7 +128,7 @@ class SuggestTest {
// if very aggressive, still no correction because locale matches with typed word only // if very aggressive, still no correction because locale matches with typed word only
} }
@Test fun `English "I" instead of Polish "i" when typing in English`() { @Test fun `English 'I' instead of Polish 'i' when typing in English`() {
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"i", "i",
listOf(suggestion("I", Int.MAX_VALUE, Locale.ENGLISH), suggestion("i", 1500000, Locale("pl"))), listOf(suggestion("I", Int.MAX_VALUE, Locale.ENGLISH), suggestion("i", 1500000, Locale("pl"))),
@ -144,7 +144,7 @@ class SuggestTest {
// todo: consider special score for case-only difference? // todo: consider special score for case-only difference?
} }
@Test fun `no English "in" instead of French "un" when typing in French`() { @Test fun `no English 'in' instead of French 'un' when typing in French`() {
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"un", "un",
listOf(suggestion("in", Int.MAX_VALUE, Locale.ENGLISH), suggestion("un", 1500000, Locale.FRENCH)), listOf(suggestion("in", Int.MAX_VALUE, Locale.ENGLISH), suggestion("un", 1500000, Locale.FRENCH)),
@ -157,7 +157,7 @@ class SuggestTest {
// not corrected because of locale matching // not corrected because of locale matching
} }
@Test fun `no "né" instead of "ne"`() { @Test fun `no 'né' instead of 'ne'`() {
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ne", "ne",
listOf(suggestion("ne", 1900000, Locale.FRENCH), suggestion("", 1900000-1, Locale.FRENCH)), listOf(suggestion("ne", 1900000, Locale.FRENCH), suggestion("", 1900000-1, Locale.FRENCH)),
@ -170,7 +170,7 @@ class SuggestTest {
// not corrected because score is lower // not corrected because score is lower
} }
@Test fun `"né" instead of "ne" if "né" in ngram context`() { @Test fun `'né' instead of 'ne' if 'né' in ngram context`() {
val locale = Locale.FRENCH val locale = Locale.FRENCH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ne", "ne",
@ -183,7 +183,7 @@ class SuggestTest {
assert(result.last()) // should be corrected assert(result.last()) // should be corrected
} }
@Test fun `"né" instead of "ne" if "né" has clearly better score in ngram context`() { @Test fun `'né' instead of 'ne' if 'né' has clearly better score in ngram context`() {
val locale = Locale.FRENCH val locale = Locale.FRENCH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ne", "ne",
@ -196,7 +196,7 @@ class SuggestTest {
assert(result.last()) // should be corrected assert(result.last()) // should be corrected
} }
@Test fun `no "né" instead of "ne" if both with same score in ngram context`() { @Test fun `no 'né' instead of 'ne' if both with same score in ngram context`() {
val locale = Locale.FRENCH val locale = Locale.FRENCH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"ne", "ne",
@ -209,7 +209,7 @@ class SuggestTest {
assert(!result.last()) // should not be corrected assert(!result.last()) // should not be corrected
} }
@Test fun `no "ne" instead of "né"`() { @Test fun `no 'ne' instead of 'né'`() {
val locale = Locale.FRENCH val locale = Locale.FRENCH
val result = shouldBeAutoCorrected( val result = shouldBeAutoCorrected(
"", "",
@ -298,7 +298,7 @@ fun suggestion(word: String, score: Int, locale: Locale) =
@Implements(DictionaryFacilitatorImpl::class) @Implements(DictionaryFacilitatorImpl::class)
class ShadowFacilitator { class ShadowFacilitator {
@Implementation @Implementation
fun getCurrentLocale() = currentTypingLocale fun getCurrentLocale(): Locale = currentTypingLocale
@Implementation @Implementation
fun hasAtLeastOneInitializedMainDictionary() = true // otherwise no autocorrect fun hasAtLeastOneInitializedMainDictionary() = true // otherwise no autocorrect
} }