From 81d1ae06758670d32b67c25bdc2cd7f866f35432 Mon Sep 17 00:00:00 2001 From: Kuniwak Date: Wed, 8 Nov 2023 07:55:07 +0900 Subject: [PATCH 1/3] Update test-helper.monkey from 0.1.2 to 0.5.0 --- Editor/DeNA.Anjin.Editor.asmdef | 4 +- Editor/Localization/ja.po | 43 +++++++ Editor/UI/Agents/UGUIMonkeyAgentEditor.cs | 150 +++++++++++++++++++++- README.md | 3 + README_ja.md | 7 +- Runtime/Agents/UGUIMonkeyAgent.cs | 81 +++++++++++- Runtime/DeNA.Anjin.asmdef | 4 +- package.json | 3 +- 8 files changed, 282 insertions(+), 13 deletions(-) diff --git a/Editor/DeNA.Anjin.Editor.asmdef b/Editor/DeNA.Anjin.Editor.asmdef index bd1b086..bf7a167 100644 --- a/Editor/DeNA.Anjin.Editor.asmdef +++ b/Editor/DeNA.Anjin.Editor.asmdef @@ -2,7 +2,9 @@ "name": "DeNA.Anjin.Editor", "rootNamespace": "DeNA.Anjin", "references": [ - "DeNA.Anjin" + "DeNA.Anjin", + "TestHelper.Monkey.Annotations", + "TestHelper.Monkey" ], "includePlatforms": [ "Editor" diff --git a/Editor/Localization/ja.po b/Editor/Localization/ja.po index b2eb6ba..75233f7 100644 --- a/Editor/Localization/ja.po +++ b/Editor/Localization/ja.po @@ -267,6 +267,49 @@ msgstr "操作間隔[ミリ秒]" msgid "Delay time between random operations [ms]" msgstr "ランダム操作ごとの遅延時間[ミリ秒]" +# timeout +msgid "Secs Searching Components" +msgstr "コンポーネント探索時間[秒]" + +# timeout tooltip +msgid "Seconds to determine that an error has occurred when an object that can be interacted with does not exist" +msgstr "インタラクティブな要素を探索する秒数を指定します。探索時間がこれを超えるとエラーを発生させます" + +# touchAndHoldDelayMillis +msgid "Touch and Hold Millis" +msgstr "タッチ&ホールド時間[ミリ秒]" + +# touchAndHoldDelayMillis tooltip +msgid "Delay time for touch-and-hold [ms]" +msgstr "タッチ&ホールドの継続時間[ミリ秒]" + +# gizmos +msgid "Enable Gizmos" +msgstr "Gizmos を有効" + +# gizmos tooltip +msgid "Show Gizmos on GameView during running monkey test if true" +msgstr "もし有効ならモンキー操作中の GameView に Gizmo を表示します。もし無効なら GameView に Gizmo を表示しません" + +# random string parameters table +msgid "Random String Parameters Table" +msgstr "ランダム文字列パラメータ表" + +# random string parameters table game object name +msgid "Game Object Name" +msgstr "Game Object の名前" + +# random string parameters table characters kind +msgid "Characters Kind" +msgstr "文字種" + +# random string parameters table minimum length +msgid "Minimum Length" +msgstr "最小文字列長" + +# random string parameters table maximum length +msgid "Maximum Length" +msgstr "最大文字列長" #: Editor/UI/Agents/UGUIPlaybackAgentEditor.cs diff --git a/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs b/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs index 6cbcdbe..7ace268 100644 --- a/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs +++ b/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using DeNA.Anjin.Agents; using UnityEditor; +using UnityEditorInternal; using UnityEngine; namespace DeNA.Anjin.Editor.UI.Agents @@ -17,25 +18,162 @@ public class UGUIMonkeyAgentEditor : UnityEditor.Editor { private static readonly string s_description = L10n.Tr("Description"); private static readonly string s_descriptionTooltip = L10n.Tr("Description about this agent instance"); + private SerializedProperty _descriptionProp; + private GUIContent _descriptionGUIContent; + private static readonly string s_lifespanSec = L10n.Tr("Lifespan Sec"); private static readonly string s_lifespanSecTooltip = L10n.Tr("Agent running lifespan [sec]. When specified zero, so unlimited running"); + private SerializedProperty _lifespanProp; + private GUIContent _lifespanGUIContent; + private static readonly string s_delayMillis = L10n.Tr("Delay Millis"); private static readonly string s_delayMillisTooltip = L10n.Tr("Delay time between random operations [ms]"); + private SerializedProperty _delayMillisProp; + private GUIContent _delayMillisGUIContent; + + private static readonly string s_timeout = + L10n.Tr("Secs Searching Components"); + + private static readonly string s_timeoutToolTip = L10n.Tr( + "Seconds to determine that an error has occurred when an object that can be interacted with does not exist" + ); + + private SerializedProperty _timeoutProp; + private GUIContent _timeoutGUIContent; + + private static readonly string s_touchAndHoldDelayMillis = L10n.Tr("Touch and Hold Millis"); + private static readonly string s_touchAndHoldDelayMillisTooltip = L10n.Tr("Delay time for touch-and-hold [ms]"); + private SerializedProperty _touchAndHoldDelayMillisProp; + private GUIContent _touchAndHoldDelayMillisGUIContent; + + private static readonly string s_gizmos = L10n.Tr("Enable Gizmos"); + + private static readonly string s_gizmosTooltip = + L10n.Tr("Show Gizmos on GameView during running monkey test if true"); + + private SerializedProperty _gizmosProp; + private GUIContent _gizmosGUIContent; + + private static readonly string s_randomStringParams = L10n.Tr("Random String Parameters Table"); + private static readonly string s_randomStringParamsEntryKey = L10n.Tr("Game Object Name"); + private static readonly string s_randomStringParamsEntryKind = L10n.Tr("Characters Kind"); + private static readonly string s_randomStringParamsEntryMinLength = L10n.Tr("Minimum Length"); + private static readonly string s_randomStringParamsEntryMaxLength = L10n.Tr("Maximum Length"); + private SerializedProperty _randomStringParametersMapProp; + private ReorderableList _randomStringParamsMapList; + private const float Padding = 2f; + private const int NumberOfLines = 4; + + private static readonly float s_elementHeight = + EditorGUIUtility.singleLineHeight * NumberOfLines + Padding * (NumberOfLines + 1); + + private GUIContent _randomStringParamsEntryKeyGUIContent; + private GUIContent _randomStringParamsEntryKindGUIContent; + private GUIContent _randomStringParamsEntryMinLengthGUIContent; + private GUIContent _randomStringParamsEntryMaxLengthGUIContent; + + + private void OnEnable() + { + Initialize(); + } + + + private void Initialize() + { + _descriptionProp = serializedObject.FindProperty(nameof(UGUIMonkeyAgent.description)); + _descriptionGUIContent = new GUIContent(s_description, s_descriptionTooltip); + + _lifespanProp = serializedObject.FindProperty(nameof(UGUIMonkeyAgent.lifespanSec)); + _lifespanGUIContent = new GUIContent(s_lifespanSec, s_lifespanSecTooltip); + + _delayMillisProp = serializedObject.FindProperty(nameof(UGUIMonkeyAgent.delayMillis)); + _delayMillisGUIContent = new GUIContent(s_delayMillis, s_delayMillisTooltip); + + _timeoutProp = + serializedObject.FindProperty(nameof(UGUIMonkeyAgent.secondsToErrorForNoInteractiveComponent)); + _timeoutGUIContent = new GUIContent(s_timeout, s_timeoutToolTip); + + _touchAndHoldDelayMillisProp = + serializedObject.FindProperty(nameof(UGUIMonkeyAgent.touchAndHoldDelayMillis)); + _touchAndHoldDelayMillisGUIContent = new GUIContent( + s_touchAndHoldDelayMillis, + s_touchAndHoldDelayMillisTooltip + ); + + _gizmosProp = serializedObject.FindProperty(nameof(UGUIMonkeyAgent.gizmos)); + _gizmosGUIContent = new GUIContent(s_gizmos, s_gizmosTooltip); + + _randomStringParamsEntryKeyGUIContent = new GUIContent(s_randomStringParamsEntryKey); + _randomStringParamsEntryKindGUIContent = new GUIContent(s_randomStringParamsEntryKind); + _randomStringParamsEntryMinLengthGUIContent = new GUIContent(s_randomStringParamsEntryMinLength); + _randomStringParamsEntryMaxLengthGUIContent = new GUIContent(s_randomStringParamsEntryMaxLength); + _randomStringParametersMapProp = + serializedObject.FindProperty(nameof(UGUIMonkeyAgent.randomStringParametersMap)); + _randomStringParamsMapList = new ReorderableList(serializedObject, _randomStringParametersMapProp) + { + drawHeaderCallback = rect => EditorGUI.LabelField(rect, s_randomStringParams), + elementHeightCallback = _ => s_elementHeight, + drawElementCallback = (rect, index, _, _) => + { + var elemProp = _randomStringParametersMapProp.GetArrayElementAtIndex(index); + var rect1 = new Rect(rect) { y = rect.y + Padding, height = EditorGUIUtility.singleLineHeight }; + EditorGUI.PropertyField( + rect1, + elemProp.FindPropertyRelative(nameof(UGUIMonkeyAgent.RandomStringParametersEntry.GameObjectName)), + _randomStringParamsEntryKeyGUIContent + ); + + var rect2 = new Rect(rect) + { + y = rect1.y + EditorGUIUtility.singleLineHeight + Padding, + height = EditorGUIUtility.singleLineHeight + }; + EditorGUI.PropertyField( + rect2, + elemProp.FindPropertyRelative(nameof(UGUIMonkeyAgent.RandomStringParametersEntry.CharactersKind)), + _randomStringParamsEntryKindGUIContent + ); + var rect3 = new Rect(rect) + { + y = rect2.y + EditorGUIUtility.singleLineHeight + Padding, + height = EditorGUIUtility.singleLineHeight + }; + EditorGUI.PropertyField( + rect3, + elemProp.FindPropertyRelative(nameof(UGUIMonkeyAgent.RandomStringParametersEntry.MinimumLength)), + _randomStringParamsEntryMinLengthGUIContent + ); + var rect4 = new Rect(rect) + { + y = rect3.y + EditorGUIUtility.singleLineHeight + Padding, + height = EditorGUIUtility.singleLineHeight + }; + EditorGUI.PropertyField( + rect4, + elemProp.FindPropertyRelative(nameof(UGUIMonkeyAgent.RandomStringParametersEntry.MaximumLength)), + _randomStringParamsEntryMaxLengthGUIContent + ); + } + }; + } + /// public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(UGUIMonkeyAgent.description)), - new GUIContent(s_description, s_descriptionTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(UGUIMonkeyAgent.lifespanSec)), - new GUIContent(s_lifespanSec, s_lifespanSecTooltip)); - EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(UGUIMonkeyAgent.delayMillis)), - new GUIContent(s_delayMillis, s_delayMillisTooltip)); + EditorGUILayout.PropertyField(_descriptionProp, _descriptionGUIContent); + EditorGUILayout.PropertyField(_lifespanProp, _lifespanGUIContent); + EditorGUILayout.PropertyField(_delayMillisProp, _delayMillisGUIContent); + EditorGUILayout.PropertyField(_timeoutProp, _timeoutGUIContent); + EditorGUILayout.PropertyField(_touchAndHoldDelayMillisProp, _touchAndHoldDelayMillisGUIContent); + EditorGUILayout.PropertyField(_gizmosProp, _gizmosGUIContent); + _randomStringParamsMapList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } diff --git a/README.md b/README.md index 0da8716..47bc86f 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,9 @@ An instance of this Agent (.asset file) can contain the following.
Lifespan Sec
Duration of random operation execution time in secounds. If 0 is specified, the operation is almost unlimited (TimeSpan.MaxValue). With this setting, neither Autopilot nor the app itself will exit when the Agent exits. It will not do anything until the next Scene switch
Delay Millis
Wait interval [milliseconds] between random operations
+
Secs Searching Components
Seconds to determine that an error has occurred when an object that can be interacted with does not exist
+
Touch and Hold Millis
Delay time for touch-and-hold [ms]
+
Enable Gizmos
Show Gizmos on GameView during running monkey test if true
If you have a `GameObject` that you want to avoid manipulation by the `UGUIMonkeyAgent`, diff --git a/README_ja.md b/README_ja.md index b7ec5bc..3b53578 100644 --- a/README_ja.md +++ b/README_ja.md @@ -215,8 +215,11 @@ uGUIのコンポーネントをランダムに操作するAgentです。 このAgentのインスタンス(.assetファイル)には以下を設定できます。
-
Lifespan Sec
ランダム操作の実行時間を秒で指定します。0を指定するとほぼ無制限(TimeSpan.MaxValue)に動作します。この設定でAgentが終了してもオートパイロットおよびアプリ自体は終了しません。次にSceneが切り替わるまでなにもしない状態になります
-
Delay Millis
ランダム操作間のウェイト間隔をミリ秒で指定します
+
実行時間
ランダム操作の実行時間を秒で指定します。0を指定するとほぼ無制限(TimeSpan.MaxValue)に動作します。この設定でAgentが終了してもオートパイロットおよびアプリ自体は終了しません。次にSceneが切り替わるまでなにもしない状態になります
+
操作間隔
ランダム操作間のウェイト間隔をミリ秒で指定します
+
コンポーネント探索時間
インタラクティブな要素を探索する秒数を指定します。探索時間がこれを超えるとエラーを発生させます
+
タッチ&ホールド時間
タッチ&ホールドの継続時間をミリ秒で指定します
+
Gizmo
もし有効ならモンキー操作中の GameView に Gizmo を表示します。もし無効なら GameView に Gizmo を表示しません
`UGUIMonkeyAgent` によって操作されたくない `GameObject` がある場合、 diff --git a/Runtime/Agents/UGUIMonkeyAgent.cs b/Runtime/Agents/UGUIMonkeyAgent.cs index a76f53a..9e57ad7 100644 --- a/Runtime/Agents/UGUIMonkeyAgent.cs +++ b/Runtime/Agents/UGUIMonkeyAgent.cs @@ -2,11 +2,14 @@ // This software is released under the MIT License. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; using Cysharp.Threading.Tasks; using TestHelper.Monkey; +using TestHelper.Monkey.Annotations.Enums; using TestHelper.Monkey.Random; +using TestHelper.Random; using UnityEngine; namespace DeNA.Anjin.Agents @@ -28,21 +31,95 @@ public class UGUIMonkeyAgent : AbstractAgent /// public int delayMillis = 200; + /// + /// Seconds to determine that an error has occurred when an object that can be interacted with does not exist + /// + public int secondsToErrorForNoInteractiveComponent = 5; + + /// + /// Delay time for touch-and-hold + /// + public int touchAndHoldDelayMillis = 1000; + + /// + /// Show Gizmos on GameView during running monkey test if true + /// + public bool gizmos; + + /// + /// Name-based random string parameters strategy. If a GameObject's name is match to the key, the random string + /// parameters will be used. If multiple entries have a same key, which entry get used is unspecified. + /// Otherwise will be used. + /// + /// + // ReSharper disable once CollectionNeverUpdated.Global + public List randomStringParametersMap = + new List(); + + /// public override async UniTask Run(CancellationToken token) { Logger.Log($"Enter {this.name}.Run()"); + var random = new RandomImpl(this.Random.Next()); var config = new MonkeyConfig { Lifetime = lifespanSec > 0 ? TimeSpan.FromSeconds(lifespanSec) : TimeSpan.MaxValue, DelayMillis = delayMillis, - Random = new RandomImpl(this.Random.Next()), - Logger = this.Logger, + Random = random, + RandomString = new RandomStringImpl(random), + RandomStringParametersStrategy = GetRandomStringParameters, + SecondsToErrorForNoInteractiveComponent = secondsToErrorForNoInteractiveComponent, + TouchAndHoldDelayMillis = touchAndHoldDelayMillis, + Gizmos = gizmos }; await Monkey.Run(config, token); Logger.Log($"Exit {this.name}.Run()"); } + + private RandomStringParameters GetRandomStringParameters(GameObject gameObject) + { + // NOTE: Random string parameters maps not get too large, so linear searching allowed in here. + for (var i = randomStringParametersMap.Count - 1; 0 <= i; i--) + { + var entry = randomStringParametersMap[i]; + if (gameObject.name == entry.GameObjectName) + { + return entry.AsRandomStringParameters(); + } + } + + return RandomStringParameters.Default; + } + + /// + /// Serializable struct for + /// + [Serializable] + public struct RandomStringParametersEntry + { + /// + /// Name of GameObjects. + /// + public string GameObjectName; + + /// + public int MinimumLength; + + /// + public int MaximumLength; + + /// + public CharactersKind CharactersKind; + + /// + /// Returns a + /// + /// + public RandomStringParameters AsRandomStringParameters() => + new RandomStringParameters(MinimumLength, MaximumLength, CharactersKind); + } } } diff --git a/Runtime/DeNA.Anjin.asmdef b/Runtime/DeNA.Anjin.asmdef index 2ae0cd2..2264852 100644 --- a/Runtime/DeNA.Anjin.asmdef +++ b/Runtime/DeNA.Anjin.asmdef @@ -5,7 +5,9 @@ "DeNA.Anjin.Annotations", "Unity.AutomatedQA", "UniTask", - "TestHelper.Monkey" + "TestHelper.Monkey", + "TestHelper.Monkey.Annotations", + "TestHelper.Random" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/package.json b/package.json index bcbdf09..4bacc10 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "changelogUrl": "https://github.com/DeNA/Anjin/releases", "dependencies": { "com.cysharp.unitask": "2.3.3", - "com.nowsprinting.test-helper.monkey": "0.1.2", + "com.nowsprinting.test-helper.monkey": "0.5.0", + "com.nowsprinting.test-helper.random": "0.1.0", "com.unity.automated-testing": "0.8.1-preview.2" }, "displayName": "Anjin", From cd0170ed6ce4987bc90e5f1557f9d75a689de9cb Mon Sep 17 00:00:00 2001 From: Kuniwak Date: Wed, 8 Nov 2023 09:41:01 +0900 Subject: [PATCH 2/3] Fix errors on Unity2019.x --- Editor/UI/Agents/UGUIMonkeyAgentEditor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs b/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs index 7ace268..dc723c3 100644 --- a/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs +++ b/Editor/UI/Agents/UGUIMonkeyAgentEditor.cs @@ -117,7 +117,10 @@ private void Initialize() { drawHeaderCallback = rect => EditorGUI.LabelField(rect, s_randomStringParams), elementHeightCallback = _ => s_elementHeight, - drawElementCallback = (rect, index, _, _) => + // XXX: Discarding parameters cannot be used on Unity 2019.x . + // ReSharper disable UnusedParameter.Local + drawElementCallback = (rect, index, isActive, isFocused) => + // ReSharper enable UnusedParameter.Local { var elemProp = _randomStringParametersMapProp.GetArrayElementAtIndex(index); var rect1 = new Rect(rect) { y = rect.y + Padding, height = EditorGUIUtility.singleLineHeight }; From 952866f7197d6a85bd9b7a5cdc4f9c576654a707 Mon Sep 17 00:00:00 2001 From: Kuniwak Date: Wed, 8 Nov 2023 14:47:20 +0900 Subject: [PATCH 3/3] Update package.json Co-authored-by: Koji Hasegawa --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4bacc10..e6441ca 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dependencies": { "com.cysharp.unitask": "2.3.3", "com.nowsprinting.test-helper.monkey": "0.5.0", - "com.nowsprinting.test-helper.random": "0.1.0", + "com.nowsprinting.test-helper.random": "0.2.0", "com.unity.automated-testing": "0.8.1-preview.2" }, "displayName": "Anjin",