Skip to content

Commit

Permalink
Merge pull request #17 from DeNA/update-test-helper-monkey
Browse files Browse the repository at this point in the history
Update test-helper.monkey
  • Loading branch information
Kuniwak authored Nov 10, 2023
2 parents 8256842 + 952866f commit 145f567
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 13 deletions.
4 changes: 3 additions & 1 deletion Editor/DeNA.Anjin.Editor.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"name": "DeNA.Anjin.Editor",
"rootNamespace": "DeNA.Anjin",
"references": [
"DeNA.Anjin"
"DeNA.Anjin",
"TestHelper.Monkey.Annotations",
"TestHelper.Monkey"
],
"includePlatforms": [
"Editor"
Expand Down
43 changes: 43 additions & 0 deletions Editor/Localization/ja.po
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
153 changes: 147 additions & 6 deletions Editor/UI/Agents/UGUIMonkeyAgentEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using DeNA.Anjin.Agents;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace DeNA.Anjin.Editor.UI.Agents
Expand All @@ -17,25 +18,165 @@ 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,
// 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 };
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
);
}
};
}


/// <inheritdoc/>
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();
}
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ An instance of this Agent (.asset file) can contain the following.
<dl>
<dt>Lifespan Sec</dt><dd>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</dd>
<dt>Delay Millis</dt><dd>Wait interval [milliseconds] between random operations</dd>
<dt>Secs Searching Components</dt><dd>Seconds to determine that an error has occurred when an object that can be interacted with does not exist</dd>
<dt>Touch and Hold Millis</dt><dd>Delay time for touch-and-hold [ms]</dd>
<dt>Enable Gizmos</dt><dd>Show Gizmos on GameView during running monkey test if true</dd>
</dl>

If you have a `GameObject` that you want to avoid manipulation by the `UGUIMonkeyAgent`,
Expand Down
7 changes: 5 additions & 2 deletions README_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,11 @@ uGUIのコンポーネントをランダムに操作するAgentです。
このAgentのインスタンス(.assetファイル)には以下を設定できます。

<dl>
<dt>Lifespan Sec</dt><dd>ランダム操作の実行時間を秒で指定します。0を指定するとほぼ無制限(TimeSpan.MaxValue)に動作します。この設定でAgentが終了してもオートパイロットおよびアプリ自体は終了しません。次にSceneが切り替わるまでなにもしない状態になります</dd>
<dt>Delay Millis</dt><dd>ランダム操作間のウェイト間隔をミリ秒で指定します</dd>
<dt>実行時間</dt><dd>ランダム操作の実行時間を秒で指定します。0を指定するとほぼ無制限(TimeSpan.MaxValue)に動作します。この設定でAgentが終了してもオートパイロットおよびアプリ自体は終了しません。次にSceneが切り替わるまでなにもしない状態になります</dd>
<dt>操作間隔</dt><dd>ランダム操作間のウェイト間隔をミリ秒で指定します</dd>
<dt>コンポーネント探索時間</dt><dd>インタラクティブな要素を探索する秒数を指定します。探索時間がこれを超えるとエラーを発生させます</dd>
<dt>タッチ&ホールド時間</dt><dd>タッチ&ホールドの継続時間をミリ秒で指定します</dd>
<dt>Gizmo</dt><dd>もし有効ならモンキー操作中の GameView に Gizmo を表示します。もし無効なら GameView に Gizmo を表示しません</dd>
</dl>

`UGUIMonkeyAgent` によって操作されたくない `GameObject` がある場合、
Expand Down
81 changes: 79 additions & 2 deletions Runtime/Agents/UGUIMonkeyAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,21 +31,95 @@ public class UGUIMonkeyAgent : AbstractAgent
/// </summary>
public int delayMillis = 200;

/// <summary>
/// Seconds to determine that an error has occurred when an object that can be interacted with does not exist
/// </summary>
public int secondsToErrorForNoInteractiveComponent = 5;

/// <summary>
/// Delay time for touch-and-hold
/// </summary>
public int touchAndHoldDelayMillis = 1000;

/// <summary>
/// Show Gizmos on <c>GameView</c> during running monkey test if true
/// </summary>
public bool gizmos;

/// <summary>
/// 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 <c cref="RandomStringParameters.Default" /> will be used.
/// </summary>
/// <returns></returns>
// ReSharper disable once CollectionNeverUpdated.Global
public List<RandomStringParametersEntry> randomStringParametersMap =
new List<RandomStringParametersEntry>();


/// <inheritdoc />
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;
}

/// <summary>
/// Serializable struct for <c cref="RandomStringParameters" />
/// </summary>
[Serializable]
public struct RandomStringParametersEntry
{
/// <summary>
/// Name of GameObjects.
/// </summary>
public string GameObjectName;

/// <inheritdoc cref="RandomStringParameters.MinimumLength" />
public int MinimumLength;

/// <inheritdoc cref="RandomStringParameters.MaximumLength" />
public int MaximumLength;

/// <inheritdoc cref="RandomStringParameters.CharactersKind" />
public CharactersKind CharactersKind;

/// <summary>
/// Returns a <c cref="RandomStringParameters" />
/// </summary>
/// <returns></returns>
public RandomStringParameters AsRandomStringParameters() =>
new RandomStringParameters(MinimumLength, MaximumLength, CharactersKind);
}
}
}
4 changes: 3 additions & 1 deletion Runtime/DeNA.Anjin.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"DeNA.Anjin.Annotations",
"Unity.AutomatedQA",
"UniTask",
"TestHelper.Monkey"
"TestHelper.Monkey",
"TestHelper.Monkey.Annotations",
"TestHelper.Random"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.2.0",
"com.unity.automated-testing": "0.8.1-preview.2"
},
"displayName": "Anjin",
Expand Down

0 comments on commit 145f567

Please sign in to comment.