暫無描述
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.

TouchInputFieldTests.cs 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. using System;
  2. using System.Linq;
  3. using NUnit.Framework;
  4. using UnityEngine;
  5. using UnityEngine.EventSystems;
  6. using UnityEngine.TestTools;
  7. using System.Collections;
  8. using System.IO;
  9. using UnityEditor;
  10. using UnityEngine.UI;
  11. using System.Reflection;
  12. namespace InputfieldTests
  13. {
  14. public class TouchInputFieldTests : BaseInputFieldTests, IPrebuildSetup
  15. {
  16. protected const string kPrefabPath = "Assets/Resources/TouchInputFieldPrefab.prefab";
  17. public void Setup()
  18. {
  19. #if UNITY_EDITOR
  20. CreateInputFieldAsset(kPrefabPath);
  21. #endif
  22. }
  23. [SetUp]
  24. public void TestSetup()
  25. {
  26. m_PrefabRoot = UnityEngine.Object.Instantiate(Resources.Load("TouchInputFieldPrefab")) as GameObject;
  27. FieldInfo inputModule = typeof(EventSystem).GetField("m_CurrentInputModule", BindingFlags.NonPublic | BindingFlags.Instance);
  28. inputModule.SetValue(m_PrefabRoot.GetComponentInChildren<EventSystem>(), m_PrefabRoot.GetComponentInChildren<FakeInputModule>());
  29. }
  30. [TearDown]
  31. public void TearDown()
  32. {
  33. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  34. TouchScreenKeyboard.hideInput = false;
  35. FontUpdateTracker.UntrackText(m_PrefabRoot.GetComponentInChildren<Text>());
  36. GameObject.DestroyImmediate(m_PrefabRoot);
  37. }
  38. [OneTimeTearDown]
  39. public void OnetimeTearDown()
  40. {
  41. #if UNITY_EDITOR
  42. AssetDatabase.DeleteAsset(kPrefabPath);
  43. #endif
  44. }
  45. protected const string kDefaultInputStr = "foobar";
  46. const string kEmailSpecialCharacters = "!#$%&'*+-/=?^_`{|}~";
  47. public struct CharValidationTestData
  48. {
  49. public string input, output;
  50. public InputField.CharacterValidation validation;
  51. public CharValidationTestData(string input, string output, InputField.CharacterValidation validation)
  52. {
  53. this.input = input;
  54. this.output = output;
  55. this.validation = validation;
  56. }
  57. public override string ToString()
  58. {
  59. // these won't properly show up if test runners UI if we don't replace it
  60. string input = this.input.Replace(kEmailSpecialCharacters, "specialchars");
  61. string output = this.output.Replace(kEmailSpecialCharacters, "specialchars");
  62. return string.Format("input={0}, output={1}, validation={2}", input, output, validation);
  63. }
  64. }
  65. [Test]
  66. [TestCase("*Azé09", "*Azé09", InputField.CharacterValidation.None)]
  67. [TestCase("*Azé09?.", "Az09", InputField.CharacterValidation.Alphanumeric)]
  68. [TestCase("Abc10x", "10", InputField.CharacterValidation.Integer)]
  69. [TestCase("-10", "-10", InputField.CharacterValidation.Integer)]
  70. [TestCase("10.0", "100", InputField.CharacterValidation.Integer)]
  71. [TestCase("10.0", "10.0", InputField.CharacterValidation.Decimal)]
  72. [TestCase(" -10.0x", "-10.0", InputField.CharacterValidation.Decimal)]
  73. [TestCase("10,0", "10,0", InputField.CharacterValidation.Decimal)]
  74. [TestCase(" -10,0x", "-10,0", InputField.CharacterValidation.Decimal)]
  75. [TestCase("A10,0 ", "10,0", InputField.CharacterValidation.Decimal)]
  76. [TestCase("A'a aaa aaa", "A'a Aaa Aaa", InputField.CharacterValidation.Name)]
  77. [TestCase("Unity-Editor", "Unity-Editor", InputField.CharacterValidation.Name)]
  78. [TestCase("Unity--Editor", "Unity-Editor", InputField.CharacterValidation.Name)]
  79. [TestCase("-UnityEditor", "Unityeditor", InputField.CharacterValidation.Name)]
  80. [TestCase(" _JOHN* (Doe)", "John Doe", InputField.CharacterValidation.Name)]
  81. [TestCase("johndoe@unity3d.com", "johndoe@unity3d.com", InputField.CharacterValidation.EmailAddress)]
  82. [TestCase(">john doe\\@unity3d.com", "johndoe@unity3d.com", InputField.CharacterValidation.EmailAddress)]
  83. [TestCase(kEmailSpecialCharacters + "@unity3d.com", kEmailSpecialCharacters + "@unity3d.com", InputField.CharacterValidation.EmailAddress)]
  84. public void HonorsCharacterValidationSettingsAssignment(string input, string output, InputField.CharacterValidation validation)
  85. {
  86. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  87. inputField.characterValidation = validation;
  88. inputField.text = input;
  89. Assert.AreEqual(output, inputField.text, string.Format("Failed character validation: input ={0}, output ={1}, validation ={2}",
  90. input.Replace(kEmailSpecialCharacters, "specialchars"),
  91. output.Replace(kEmailSpecialCharacters, "specialchars"),
  92. validation));
  93. }
  94. [UnityTest]
  95. [TestCase("*Azé09", "*Azé09", InputField.CharacterValidation.None, ExpectedResult = null)]
  96. [TestCase("*Azé09?.", "Az09", InputField.CharacterValidation.Alphanumeric, ExpectedResult = null)]
  97. [TestCase("Abc10x", "10", InputField.CharacterValidation.Integer, ExpectedResult = null)]
  98. [TestCase("-10", "-10", InputField.CharacterValidation.Integer, ExpectedResult = null)]
  99. [TestCase("10.0", "100", InputField.CharacterValidation.Integer, ExpectedResult = null)]
  100. [TestCase("10.0", "10.0", InputField.CharacterValidation.Decimal, ExpectedResult = null)]
  101. [TestCase(" -10.0x", "-10.0", InputField.CharacterValidation.Decimal, ExpectedResult = null)]
  102. [TestCase("10,0", "10,0", InputField.CharacterValidation.Decimal, ExpectedResult = null)]
  103. [TestCase(" -10,0x", "-10,0", InputField.CharacterValidation.Decimal, ExpectedResult = null)]
  104. [TestCase("A10,0 ", "10,0", InputField.CharacterValidation.Decimal, ExpectedResult = null)]
  105. [TestCase("A'a aaa aaa", "A'a Aaa Aaa", InputField.CharacterValidation.Name, ExpectedResult = null)]
  106. [TestCase(" _JOHN* (Doe)", "John Doe", InputField.CharacterValidation.Name, ExpectedResult = null)]
  107. [TestCase("johndoe@unity3d.com", "johndoe@unity3d.com", InputField.CharacterValidation.EmailAddress, ExpectedResult = null)]
  108. [TestCase(">john doe\\@unity3d.com", "johndoe@unity3d.com", InputField.CharacterValidation.EmailAddress, ExpectedResult = null)]
  109. [TestCase(kEmailSpecialCharacters + "@unity3d.com", kEmailSpecialCharacters + "@unity3d.com", InputField.CharacterValidation.EmailAddress, ExpectedResult = null)]
  110. public IEnumerator HonorsCharacterValidationSettingsTypingWithSelection(string input, string output, InputField.CharacterValidation validation)
  111. {
  112. if (!TouchScreenKeyboard.isSupported)
  113. yield break;
  114. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  115. BaseEventData eventData = new BaseEventData(m_PrefabRoot.GetComponentInChildren<EventSystem>());
  116. inputField.characterValidation = validation;
  117. inputField.text = input;
  118. #if UNITY_GAMECORE && !UNITY_EDITOR
  119. // Address instabilities: UUM-34900, UUM-32902
  120. // Cause:
  121. // On Xbox devkits, the PLM (Process Lifetime Management) suspends the application when the on-screen keyboard is opened.
  122. // This cause subsequent tests to fail because the event system will ignore input when the application is not focused.
  123. // Resolution:
  124. // Yielding any call that trigger OSK (open and closure) to ensure the OSK is in the expected stated before continuing the test.
  125. // Note:
  126. // UNITY_GAMECORE affects all GDK compatible platforms (Xbox One, Series and Windows).
  127. // As PLM is only a GDK for consoles feature, this fix have to be enforced on console platforms only.
  128. do
  129. {
  130. inputField.OnSelect(eventData);
  131. yield return null;
  132. }
  133. while (!TouchScreenKeyboard.visible);
  134. #else
  135. inputField.OnSelect(eventData);
  136. yield return null;
  137. #endif
  138. Assert.AreEqual(output, inputField.text, string.Format("Failed character validation: input ={0}, output ={1}, validation ={2}",
  139. input.Replace(kEmailSpecialCharacters, "specialchars"),
  140. output.Replace(kEmailSpecialCharacters, "specialchars"),
  141. validation));
  142. #if UNITY_GAMECORE && !UNITY_EDITOR
  143. do
  144. {
  145. // We manually close the OSK as we don't need to assert the inputField afterward.
  146. if (inputField.touchScreenKeyboard != null)
  147. {
  148. inputField.touchScreenKeyboard.active = false;
  149. }
  150. // No delay is needed here as we don't use inputField.OnDeselect.
  151. yield return null;
  152. }
  153. while (TouchScreenKeyboard.visible);
  154. #endif
  155. }
  156. [Test]
  157. public void AssignmentAgainstCharacterLimit([Values("ABC", "abcdefghijkl")] string text)
  158. {
  159. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  160. // test assignment
  161. inputField.characterLimit = 5;
  162. inputField.text = text;
  163. Assert.AreEqual(text.Substring(0, Math.Min(text.Length, inputField.characterLimit)), inputField.text);
  164. }
  165. [Test] // regression test 793119
  166. public void AssignmentAgainstCharacterLimitWithContentType([Values("Abc", "Abcdefghijkl")] string text)
  167. {
  168. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  169. // test assignment
  170. inputField.characterLimit = 5;
  171. inputField.contentType = InputField.ContentType.Name;
  172. inputField.text = text;
  173. Assert.AreEqual(text.Substring(0, Math.Min(text.Length, inputField.characterLimit)), inputField.text);
  174. }
  175. [UnityTest]
  176. [UnityPlatform(exclude = new[] { RuntimePlatform.tvOS })] // UUM-71764 (tvOS)
  177. public IEnumerator SendsEndEditEventOnDeselect()
  178. {
  179. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  180. BaseEventData eventData = new BaseEventData(m_PrefabRoot.GetComponentInChildren<EventSystem>());
  181. #if UNITY_GAMECORE && !UNITY_EDITOR
  182. do
  183. {
  184. inputField.OnSelect(eventData);
  185. // If 2 tests trying to open and close the OSK are called in a row, the seconds test would always hang for 2 to 3 minutes.
  186. // This seemed to happens everytime the OSK is disabled using input.OnDeselect before being re-enabled using input.OnSelect.
  187. // Adding these 0.2s delay on in these case allows to get rid of the hang.
  188. yield return new WaitForSecondsRealtime(0.2f);
  189. }
  190. while (!TouchScreenKeyboard.visible);
  191. #else
  192. inputField.OnSelect(eventData);
  193. yield return null;
  194. #endif
  195. var called = false;
  196. inputField.onEndEdit.AddListener((s) => { called = true; });
  197. #if UNITY_GAMECORE && !UNITY_EDITOR
  198. do
  199. {
  200. inputField.OnDeselect(eventData);
  201. yield return new WaitForSecondsRealtime(0.2f);
  202. }
  203. while (TouchScreenKeyboard.visible);
  204. #else
  205. inputField.OnDeselect(eventData);
  206. #endif
  207. Assert.IsTrue(called, "Expected invocation of onEndEdit");
  208. }
  209. [Test]
  210. public void StripsNullCharacters2()
  211. {
  212. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  213. inputField.text = "a\0b";
  214. Assert.AreEqual("ab", inputField.text, "\\0 characters should be stripped");
  215. }
  216. [UnityTest]
  217. [UnityPlatform(exclude = new[] { RuntimePlatform.tvOS })] // UUM-71764 (tvOS)
  218. public IEnumerator FocusOpensTouchScreenKeyboard()
  219. {
  220. var isInPlaceEditingDisabled = typeof(TouchScreenKeyboard).GetProperty("disableInPlaceEditing",
  221. System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
  222. isInPlaceEditingDisabled.SetValue(null, true);
  223. if (!TouchScreenKeyboard.isSupported)
  224. yield break;
  225. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  226. BaseEventData eventData = new BaseEventData(m_PrefabRoot.GetComponentInChildren<EventSystem>());
  227. #if UNITY_GAMECORE && !UNITY_EDITOR
  228. do
  229. {
  230. inputField.OnSelect(eventData);
  231. yield return new WaitForSecondsRealtime(0.2f);
  232. }
  233. while (!TouchScreenKeyboard.visible);
  234. #else
  235. inputField.OnSelect(eventData);
  236. yield return null;
  237. #endif
  238. Assert.NotNull(inputField.touchScreenKeyboard, "Expect a keyboard to be opened");
  239. #if UNITY_GAMECORE && !UNITY_EDITOR
  240. do
  241. {
  242. inputField.OnDeselect(eventData);
  243. yield return new WaitForSecondsRealtime(0.2f);
  244. }
  245. while (TouchScreenKeyboard.visible);
  246. #endif
  247. }
  248. [UnityTest]
  249. public IEnumerator AssignsShouldHideInput()
  250. {
  251. if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
  252. {
  253. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  254. BaseEventData eventData = new BaseEventData(m_PrefabRoot.GetComponentInChildren<EventSystem>());
  255. inputField.shouldHideMobileInput = false;
  256. inputField.OnSelect(eventData);
  257. yield return null;
  258. Assert.IsFalse(inputField.shouldHideMobileInput);
  259. Assert.IsFalse(TouchScreenKeyboard.hideInput, "Expect TouchScreenKeyboard.hideInput to be set");
  260. }
  261. }
  262. [UnityTest, Ignore("Disabled for Instability https://jira.unity3d.com/browse/UUM-69542")]
  263. [UnityPlatform(exclude = new[] { RuntimePlatform.IPhonePlayer, RuntimePlatform.PS4, RuntimePlatform.PS5, RuntimePlatform.VisionOS })] // disabled on visionOS due to UUM-61018
  264. public IEnumerator IsTouchScreenKeyboardVisible()
  265. {
  266. const float ActionTimeout = 3.0f;
  267. if (!TouchScreenKeyboard.isSupported)
  268. yield break;
  269. InputField inputField = m_PrefabRoot.GetComponentInChildren<InputField>();
  270. BaseEventData eventData = new BaseEventData(m_PrefabRoot.GetComponentInChildren<EventSystem>());
  271. inputField.OnSelect(eventData);
  272. yield return WaitForCondition("Waiting for keyboard to show", () => TouchScreenKeyboard.visible, ActionTimeout);
  273. inputField.OnDeselect(eventData);
  274. yield return WaitForCondition("Waiting for keyboard to close", () => !TouchScreenKeyboard.visible, ActionTimeout);
  275. }
  276. }
  277. }