Skip to content

Commit dd60ab6

Browse files
authored
Merge pull request #275 from nowsprinting/chore/paginator
Remove componentType property from paginators
2 parents b76e148 + ab23501 commit dd60ab6

File tree

8 files changed

+94
-42
lines changed

8 files changed

+94
-42
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,13 @@ public class MyIntegrationTest
159159
public async Task FindButtonInScrollView()
160160
{
161161
var finder = new GameObjectFinder();
162-
var matcher = new NameMatcher("Button_10");
163162

164-
var scrollView = GameObject.Find("Scroll View");
165-
var scrollRect = scrollView.GetComponent<ScrollRect>();
163+
var scrollViewMatcher = new NameMatcher("Scroll View");
164+
var scrollViewResult = await finder.FindByMatcherAsync(scrollViewMatcher);
165+
var scrollRect = scrollViewResult.GameObject.GetComponent<ScrollRect>();
166166
var paginator = new UguiScrollRectPaginator(scrollRect);
167167

168+
var matcher = new NameMatcher("Button_10");
168169
var result = await finder.FindByMatcherAsync(matcher, paginator: paginator);
169170
var button = result.GameObject;
170171
}
@@ -468,13 +469,18 @@ For example, the built-in `ButtonMatcher` class's `IsMatch` method returns `true
468469
If your game title uses a custom pageable or scrollable UI components (e.g., Scroller, Carousel, Paged dialog), you can implement the `IPaginator` interface.
469470
The custom paginator can be specified as an argument to the `GameObjectFinder.FindByMatcherAsync` method.
470471

471-
A paginator must implement the following methods and properties:
472+
A paginator must implement the following methods:
472473

473-
- `ComponentType` property to return the type of UI component that the paginator controls
474474
- `ResetAsync` method to navigate to the top page
475475
- `NextPageAsync` method to navigate to the next page
476476
- `HasNextPage` property to return whether there is a next page
477477

478+
In addition, the constructor must meet the following requirements:
479+
480+
- A paginator must have a constructor with one or more parameters
481+
- The first parameter of the constructor is a pageable or scrollable component to be controlled
482+
- The type of the first parameter must be a subclass of `MonoBehaviour`
483+
478484

479485

480486
### IOperator interface

Runtime/Paginators/IPaginator.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2023-2025 Koji Hasegawa.
22
// This software is released under the MIT License.
33

4-
using System;
4+
using System.Diagnostics.CodeAnalysis;
55
using System.Threading;
66
using Cysharp.Threading.Tasks;
77

@@ -11,13 +11,18 @@ namespace TestHelper.UI.Paginators
1111
/// Interface for pagination controller for finding <c>GameObject</c> on pageable or scrollable UI components (e.g., <c>ScrollRect</c>, Carousel, Paged dialog).
1212
/// Provides intuitive pagination operations as page navigation functionality, enabling auxiliary operations in the <see cref="GameObjectFinder"/>.
1313
/// </summary>
14+
/// <remarks>
15+
/// The implementation class must meet the following requirements:
16+
/// <list type="bullet">
17+
/// <item>A paginator must have a constructor with one or more parameters</item>
18+
/// <item>The first parameter of the constructor is a pageable or scrollable component to be controlled</item>
19+
/// <item>The type of the first parameter must be a subclass of <c>MonoBehaviour</c></item>
20+
/// </list>
21+
/// <seealso cref="TestHelper.UI.Paginators.IPaginatorTest"/>
22+
/// </remarks>
23+
[SuppressMessage("ReSharper", "InvalidXmlDocComment")]
1424
public interface IPaginator
1525
{
16-
/// <summary>
17-
/// Pageable or scrollable UI component type.
18-
/// </summary>
19-
Type ComponentType { get; }
20-
2126
/// <summary>
2227
/// Move the page position to the beginning.
2328
/// For scroll components, the display position (top, bottom, left, or right) depends on the implementation.

Runtime/Paginators/UguiScrollRectPaginator.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@ namespace TestHelper.UI.Paginators
1414
/// </summary>
1515
public class UguiScrollRectPaginator : IPaginator
1616
{
17-
/// <inheritdoc />
18-
public Type ComponentType => typeof(ScrollRect);
19-
2017
private readonly ScrollRect _scrollRect;
2118
private bool _isHorizontalAtEnd;
2219

2320
/// <summary>
24-
/// Constructor.
21+
/// Constructor that takes a scroller instance.
2522
/// </summary>
2623
/// <param name="scrollRect">ScrollRect to be controlled</param>
2724
/// <exception cref="ArgumentNullException">When scrollRect is null</exception>
2825
public UguiScrollRectPaginator(ScrollRect scrollRect)
2926
{
30-
_scrollRect = scrollRect ?? throw new ArgumentNullException(nameof(scrollRect));
27+
if (!scrollRect)
28+
{
29+
throw new ArgumentNullException(nameof(scrollRect));
30+
}
3131

32-
if (_scrollRect.content == null)
32+
if (!scrollRect.content)
3333
{
3434
throw new ArgumentNullException(nameof(scrollRect.content), "ScrollRect.content is null");
3535
}
36+
37+
_scrollRect = scrollRect;
3638
}
3739

3840
/// <inheritdoc />

Runtime/Paginators/UguiScrollbarPaginator.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,21 @@ namespace TestHelper.UI.Paginators
1414
/// </summary>
1515
public class UguiScrollbarPaginator : IPaginator
1616
{
17-
/// <inheritdoc />
18-
public Type ComponentType => typeof(Scrollbar);
19-
2017
private readonly Scrollbar _scrollbar;
2118

2219
/// <summary>
23-
/// Constructor.
20+
/// Constructor that takes a scroller instance.
2421
/// </summary>
2522
/// <param name="scrollbar">Scrollbar to be controlled</param>
2623
/// <exception cref="ArgumentNullException">When scrollbar is null</exception>
2724
public UguiScrollbarPaginator(Scrollbar scrollbar)
2825
{
29-
_scrollbar = scrollbar ?? throw new ArgumentNullException(nameof(scrollbar));
26+
if (!scrollbar)
27+
{
28+
throw new ArgumentNullException(nameof(scrollbar));
29+
}
30+
31+
_scrollbar = scrollbar;
3032
}
3133

3234
/// <inheritdoc />
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2023-2025 Koji Hasegawa.
2+
// This software is released under the MIT License.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Reflection;
7+
using NUnit.Framework;
8+
using UnityEngine;
9+
10+
namespace TestHelper.UI.Paginators
11+
{
12+
[TestFixture]
13+
public class IPaginatorTest
14+
{
15+
private static Type[] GetPaginators()
16+
{
17+
var interfaceType = typeof(IPaginator);
18+
return AppDomain.CurrentDomain.GetAssemblies()
19+
.SelectMany(assembly =>
20+
{
21+
try
22+
{
23+
return assembly.GetTypes();
24+
}
25+
catch (ReflectionTypeLoadException ex)
26+
{
27+
return ex.Types.Where(t => t != null);
28+
}
29+
catch
30+
{
31+
return Enumerable.Empty<Type>();
32+
}
33+
})
34+
.Where(t => t != null && interfaceType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
35+
.ToArray();
36+
}
37+
38+
/// <summary>
39+
/// Verify that the paginators and supported component type can be obtained via reflection.
40+
/// </summary>
41+
[TestCaseSource(nameof(GetPaginators))]
42+
public void Constructor_HasOneParameterAndSubclassOfMonoBehaviour(Type paginatorType)
43+
{
44+
var ctor = paginatorType.GetConstructors()
45+
.OrderBy(x => x.GetParameters().Length)
46+
.FirstOrDefault(x => x.GetParameters().Length > 0);
47+
Assume.That(ctor, Is.Not.Null, "A paginator must have a constructor with one or more parameters.");
48+
49+
var parameterType = ctor.GetParameters()[0].ParameterType;
50+
Assert.That(parameterType.IsSubclassOf(typeof(MonoBehaviour)), Is.True,
51+
"The first parameter of the constructor is a pageable or scrollable component to be controlled, which must be a subclass of MonoBehaviour.");
52+
}
53+
}
54+
}

Tests/Runtime/Paginators/IPaginatorTest.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tests/Runtime/Paginators/UguiScrollRectPaginatorTest.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,6 @@ public void SetUp()
2626
_bothScrollView = GameObject.Find("Both Scroll View");
2727
}
2828

29-
[Test]
30-
[LoadScene(TestScene)]
31-
public void ComponentType_ReturnsScrollbar()
32-
{
33-
var scrollRect = _horizontalScrollView.GetComponent<ScrollRect>();
34-
var sut = new UguiScrollRectPaginator(scrollRect);
35-
36-
Assert.That(sut.ComponentType, Is.EqualTo(typeof(ScrollRect)));
37-
}
38-
3929
[Test]
4030
[LoadScene(TestScene)]
4131
public void Constructor_ValidScrollRect_ObjectCreatedSuccessfully()

Tests/Runtime/Paginators/UguiScrollbarPaginatorTest.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,6 @@ public void SetUp()
4343
}
4444
}
4545

46-
[Test]
47-
[LoadScene(TestScene)]
48-
public void ComponentType_ReturnsScrollbar()
49-
{
50-
var scrollbar = _horizontalScrollbar.GetComponent<Scrollbar>();
51-
var sut = new UguiScrollbarPaginator(scrollbar);
52-
53-
Assert.That(sut.ComponentType, Is.EqualTo(typeof(Scrollbar)));
54-
}
55-
5646
[Test]
5747
[LoadScene(TestScene)]
5848
public void Constructor_ValidScrollbar_ObjectCreatedSuccessfully()

0 commit comments

Comments
 (0)