TestPair.Helpers.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #nullable enable
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Linq;
  5. using Content.Server.Preferences.Managers;
  6. using Content.Shared.Preferences;
  7. using Content.Shared.Roles;
  8. using Robust.Shared.GameObjects;
  9. using Robust.Shared.Map;
  10. using Robust.Shared.Network;
  11. using Robust.Shared.Prototypes;
  12. using Robust.UnitTesting;
  13. namespace Content.IntegrationTests.Pair;
  14. // Contains misc helper functions to make writing tests easier.
  15. public sealed partial class TestPair
  16. {
  17. /// <summary>
  18. /// Creates a map, a grid, and a tile, and gives back references to them.
  19. /// </summary>
  20. [MemberNotNull(nameof(TestMap))]
  21. public async Task<TestMapData> CreateTestMap(bool initialized = true, string tile = "Plating")
  22. {
  23. var mapData = new TestMapData();
  24. TestMap = mapData;
  25. await Server.WaitIdleAsync();
  26. var tileDefinitionManager = Server.ResolveDependency<ITileDefinitionManager>();
  27. TestMap = mapData;
  28. await Server.WaitPost(() =>
  29. {
  30. mapData.MapUid = Server.System<SharedMapSystem>().CreateMap(out mapData.MapId, runMapInit: initialized);
  31. mapData.Grid = Server.MapMan.CreateGridEntity(mapData.MapId);
  32. mapData.GridCoords = new EntityCoordinates(mapData.Grid, 0, 0);
  33. var plating = tileDefinitionManager[tile];
  34. var platingTile = new Tile(plating.TileId);
  35. Server.System<SharedMapSystem>().SetTile(mapData.Grid.Owner, mapData.Grid.Comp, mapData.GridCoords, platingTile);
  36. mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId);
  37. mapData.Tile = Server.System<SharedMapSystem>().GetAllTiles(mapData.Grid.Owner, mapData.Grid.Comp).First();
  38. });
  39. TestMap = mapData;
  40. if (!Settings.Connected)
  41. return mapData;
  42. await RunTicksSync(10);
  43. mapData.CMapUid = ToClientUid(mapData.MapUid);
  44. mapData.CGridUid = ToClientUid(mapData.Grid);
  45. mapData.CGridCoords = new EntityCoordinates(mapData.CGridUid, 0, 0);
  46. TestMap = mapData;
  47. return mapData;
  48. }
  49. /// <summary>
  50. /// Convert a client-side uid into a server-side uid
  51. /// </summary>
  52. public EntityUid ToServerUid(EntityUid uid) => ConvertUid(uid, Client, Server);
  53. /// <summary>
  54. /// Convert a server-side uid into a client-side uid
  55. /// </summary>
  56. public EntityUid ToClientUid(EntityUid uid) => ConvertUid(uid, Server, Client);
  57. private static EntityUid ConvertUid(
  58. EntityUid uid,
  59. RobustIntegrationTest.IntegrationInstance source,
  60. RobustIntegrationTest.IntegrationInstance destination)
  61. {
  62. if (!uid.IsValid())
  63. return EntityUid.Invalid;
  64. if (!source.EntMan.TryGetComponent<MetaDataComponent>(uid, out var meta))
  65. {
  66. Assert.Fail($"Failed to resolve MetaData while converting the EntityUid for entity {uid}");
  67. return EntityUid.Invalid;
  68. }
  69. if (!destination.EntMan.TryGetEntity(meta.NetEntity, out var otherUid))
  70. {
  71. Assert.Fail($"Failed to resolve net ID while converting the EntityUid entity {source.EntMan.ToPrettyString(uid)}");
  72. return EntityUid.Invalid;
  73. }
  74. return otherUid.Value;
  75. }
  76. /// <summary>
  77. /// Execute a command on the server and wait some number of ticks.
  78. /// </summary>
  79. public async Task WaitCommand(string cmd, int numTicks = 10)
  80. {
  81. await Server.ExecuteCommand(cmd);
  82. await RunTicksSync(numTicks);
  83. }
  84. /// <summary>
  85. /// Execute a command on the client and wait some number of ticks.
  86. /// </summary>
  87. public async Task WaitClientCommand(string cmd, int numTicks = 10)
  88. {
  89. await Client.ExecuteCommand(cmd);
  90. await RunTicksSync(numTicks);
  91. }
  92. /// <summary>
  93. /// Retrieve all entity prototypes that have some component.
  94. /// </summary>
  95. public List<(EntityPrototype, T)> GetPrototypesWithComponent<T>(
  96. HashSet<string>? ignored = null,
  97. bool ignoreAbstract = true,
  98. bool ignoreTestPrototypes = true)
  99. where T : IComponent
  100. {
  101. var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(T));
  102. var list = new List<(EntityPrototype, T)>();
  103. foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
  104. {
  105. if (ignored != null && ignored.Contains(proto.ID))
  106. continue;
  107. if (ignoreAbstract && proto.Abstract)
  108. continue;
  109. if (ignoreTestPrototypes && IsTestPrototype(proto))
  110. continue;
  111. if (proto.Components.TryGetComponent(id, out var cmp))
  112. list.Add((proto, (T)cmp));
  113. }
  114. return list;
  115. }
  116. /// <summary>
  117. /// Retrieve all entity prototypes that have some component.
  118. /// </summary>
  119. public List<EntityPrototype> GetPrototypesWithComponent(Type type,
  120. HashSet<string>? ignored = null,
  121. bool ignoreAbstract = true,
  122. bool ignoreTestPrototypes = true)
  123. {
  124. var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(type);
  125. var list = new List<EntityPrototype>();
  126. foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
  127. {
  128. if (ignored != null && ignored.Contains(proto.ID))
  129. continue;
  130. if (ignoreAbstract && proto.Abstract)
  131. continue;
  132. if (ignoreTestPrototypes && IsTestPrototype(proto))
  133. continue;
  134. if (proto.Components.ContainsKey(id))
  135. list.Add((proto));
  136. }
  137. return list;
  138. }
  139. /// <summary>
  140. /// Set a user's antag preferences. Modified preferences are automatically reset at the end of the test.
  141. /// </summary>
  142. public async Task SetAntagPreference(ProtoId<AntagPrototype> id, bool value, NetUserId? user = null)
  143. {
  144. user ??= Client.User!.Value;
  145. if (user is not {} userId)
  146. return;
  147. var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
  148. var prefs = prefMan.GetPreferences(userId);
  149. // Automatic preference resetting only resets slot 0.
  150. Assert.That(prefs.SelectedCharacterIndex, Is.EqualTo(0));
  151. var profile = (HumanoidCharacterProfile) prefs.Characters[0];
  152. var newProfile = profile.WithAntagPreference(id, value);
  153. _modifiedProfiles.Add(userId);
  154. await Server.WaitPost(() => prefMan.SetProfile(userId, 0, newProfile).Wait());
  155. }
  156. /// <summary>
  157. /// Set a user's job preferences. Modified preferences are automatically reset at the end of the test.
  158. /// </summary>
  159. public async Task SetJobPriority(ProtoId<JobPrototype> id, JobPriority value, NetUserId? user = null)
  160. {
  161. user ??= Client.User!.Value;
  162. if (user is { } userId)
  163. await SetJobPriorities(userId, (id, value));
  164. }
  165. /// <inheritdoc cref="SetJobPriority"/>
  166. public async Task SetJobPriorities(params (ProtoId<JobPrototype>, JobPriority)[] priorities)
  167. => await SetJobPriorities(Client.User!.Value, priorities);
  168. /// <inheritdoc cref="SetJobPriority"/>
  169. public async Task SetJobPriorities(NetUserId user, params (ProtoId<JobPrototype>, JobPriority)[] priorities)
  170. {
  171. var highCount = priorities.Count(x => x.Item2 == JobPriority.High);
  172. Assert.That(highCount, Is.LessThanOrEqualTo(1), "Cannot have more than one high priority job");
  173. var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
  174. var prefs = prefMan.GetPreferences(user);
  175. var profile = (HumanoidCharacterProfile) prefs.Characters[0];
  176. var dictionary = new Dictionary<ProtoId<JobPrototype>, JobPriority>(profile.JobPriorities);
  177. // Automatic preference resetting only resets slot 0.
  178. Assert.That(prefs.SelectedCharacterIndex, Is.EqualTo(0));
  179. if (highCount != 0)
  180. {
  181. foreach (var (key, priority) in dictionary)
  182. {
  183. if (priority == JobPriority.High)
  184. dictionary[key] = JobPriority.Medium;
  185. }
  186. }
  187. foreach (var (job, priority) in priorities)
  188. {
  189. if (priority == JobPriority.Never)
  190. dictionary.Remove(job);
  191. else
  192. dictionary[job] = priority;
  193. }
  194. var newProfile = profile.WithJobPriorities(dictionary);
  195. _modifiedProfiles.Add(user);
  196. await Server.WaitPost(() => prefMan.SetProfile(user, 0, newProfile).Wait());
  197. }
  198. }