Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tag component and test #2761

Merged
merged 6 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Content.Client/IgnoredComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ public static class IgnoredComponents
"MachinePart",
"MachineFrame",
"MachineBoard",
"ChemicalAmmo"
"ChemicalAmmo",
"Tag"
};
}
}
125 changes: 125 additions & 0 deletions Content.IntegrationTests/Tests/Tag/TagTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Tag;
using NUnit.Framework;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Map;

namespace Content.IntegrationTests.Tests.Tag
{
[TestFixture]
[TestOf(typeof(TagComponent))]
public class TagTest : ContentIntegrationTest
{
private static readonly string TagEntityId = "TagTestDummy";

private static readonly string StartingTag = "A";

private static readonly string AddedTag = "EIOU";

private static readonly string Prototypes = $@"
- type: entity
id: {TagEntityId}
name: {TagEntityId}
components:
- type: Tag
tags:
- {StartingTag}";

[Test]
public async Task TagComponentTest()
{
var options = new ServerContentIntegrationOption {ExtraPrototypes = Prototypes};
var server = StartServerDummyTicker(options);

await server.WaitIdleAsync();

var sMapManager = server.ResolveDependency<IMapManager>();
var sEntityManager = server.ResolveDependency<IEntityManager>();

TagComponent sTagComponent = null;

await server.WaitPost(() =>
{
sMapManager.CreateNewMapEntity(MapId.Nullspace);
var sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace);
sTagComponent = sTagDummy.GetComponent<TagComponent>();
});

await server.WaitAssertion(() =>
{
// Has one tag, the starting tag
Assert.That(sTagComponent.Tags.Count, Is.EqualTo(1));
Assert.That(sTagComponent.Tags, Contains.Item(StartingTag));

// Cannot add the starting tag again
Assert.That(sTagComponent.AddTag(StartingTag), Is.False);
Assert.That(sTagComponent.AddTags(StartingTag, StartingTag), Is.False);
Assert.That(sTagComponent.AddTags(new List<string> {StartingTag, StartingTag}), Is.False);

// Has the starting tag
Assert.That(sTagComponent.HasTag(StartingTag), Is.True);
Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True);
Assert.That(sTagComponent.HasAllTags(new List<string> {StartingTag, StartingTag}), Is.True);
Assert.That(sTagComponent.HasAnyTag(StartingTag, StartingTag), Is.True);
Assert.That(sTagComponent.HasAnyTag(new List<string> {StartingTag, StartingTag}), Is.True);

// Does not have the added tag yet
Assert.That(sTagComponent.HasTag(AddedTag), Is.False);
Assert.That(sTagComponent.HasAllTags(AddedTag, AddedTag), Is.False);
Assert.That(sTagComponent.HasAllTags(new List<string> {AddedTag, AddedTag}), Is.False);
Assert.That(sTagComponent.HasAnyTag(AddedTag, AddedTag), Is.False);
Assert.That(sTagComponent.HasAnyTag(new List<string> {AddedTag, AddedTag}), Is.False);

// Has a combination of the two tags
Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True);
Assert.That(sTagComponent.HasAnyTag(new List<string> {StartingTag, AddedTag}), Is.True);

// Does not have both tags
Assert.That(sTagComponent.HasAllTags(StartingTag, AddedTag), Is.False);
Assert.That(sTagComponent.HasAllTags(new List<string> {StartingTag, AddedTag}), Is.False);

// Cannot remove a tag that does not exist
Assert.That(sTagComponent.RemoveTag(AddedTag), Is.False);
Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.False);
Assert.That(sTagComponent.RemoveTags(new List<string> {AddedTag, AddedTag}), Is.False);

// Can add the new tag
Assert.That(sTagComponent.AddTag(AddedTag), Is.True);

// Cannot add it twice
Assert.That(sTagComponent.AddTag(AddedTag), Is.False);

// Cannot add existing tags
Assert.That(sTagComponent.AddTags(StartingTag, AddedTag), Is.False);
Assert.That(sTagComponent.AddTags(new List<string> {StartingTag, AddedTag}), Is.False);

// Now has two tags
Assert.That(sTagComponent.Tags.Count, Is.EqualTo(2));

// Has both tags
Assert.That(sTagComponent.HasTag(StartingTag), Is.True);
Assert.That(sTagComponent.HasTag(AddedTag), Is.True);
Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True);
Assert.That(sTagComponent.HasAllTags(AddedTag, StartingTag), Is.True);
Assert.That(sTagComponent.HasAllTags(new List<string> {StartingTag, AddedTag}), Is.True);
Assert.That(sTagComponent.HasAllTags(new List<string> {AddedTag, StartingTag}), Is.True);
Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True);
Assert.That(sTagComponent.HasAnyTag(AddedTag, StartingTag), Is.True);

// Remove the existing starting tag
Assert.That(sTagComponent.RemoveTag(StartingTag), Is.True);

// Remove the existing added tag
Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.True);

// No tags left to remove
Assert.That(sTagComponent.RemoveTags(new List<string> {StartingTag, AddedTag}), Is.False);

// No tags left in the component
Assert.That(sTagComponent.Tags, Is.Empty);
});
}
}
}
137 changes: 137 additions & 0 deletions Content.Server/GameObjects/Components/Tag/TagComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;

namespace Content.Server.GameObjects.Components.Tag
{
[RegisterComponent]
public class TagComponent : Component
{
public override string Name => "Tag";

private HashSet<string> _tags = new(0);

public IReadOnlySet<string> Tags => _tags;

public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);

serializer.DataField(ref _tags, "tags", new HashSet<string>(0));
}

/// <summary>
/// Tries to add a tag if it doesn't already exist.
/// </summary>
/// <param name="tag">The tag to add.</param>
/// <returns>true if it was added, false if it already existed.</returns>
public bool AddTag(string tag)
{
return _tags.Add(tag);
}

/// <summary>
/// Tries to add the given tags if they don't already exist.
/// </summary>
/// <param name="tags">The tags to add.</param>
/// <returns>true if any tags were added, false if it they all already existed.</returns>
public bool AddTags(params string[] tags)
{
return AddTags(tags.AsEnumerable());
}

public bool AddTags(IEnumerable<string> tags)
{
var count = _tags.Count;

_tags.UnionWith(tags);

return _tags.Count > count;
}

/// <summary>
/// Checks if a tag has been added.
/// </summary>
/// <param name="tag">The tag to check for.</param>
/// <returns>true if it exists, false otherwise.</returns>
public bool HasTag(string tag)
{
return _tags.Contains(tag);
}

/// <summary>
/// Checks if all of the given tags have been added.
/// </summary>
/// <param name="tags">The tags to check for.</param>
/// <returns>true if they all exist, false otherwise.</returns>
public bool HasAllTags(params string[] tags)
{
return HasAllTags(tags.AsEnumerable());
}

/// <summary>
/// Checks if all of the given tags have been added.
/// </summary>
/// <param name="tags">The tags to check for.</param>
/// <returns>true if they all exist, false otherwise.</returns>
public bool HasAllTags(IEnumerable<string> tags)
{
return _tags.IsSupersetOf(tags);
}

/// <summary>
/// Checks if any of the given tags have been added.
/// </summary>
/// <param name="tags">The tags to check for.</param>
/// <returns>true if any of them exist, false otherwise.</returns>
public bool HasAnyTag(params string[] tags)
{
return HasAnyTag(tags.AsEnumerable());
}

/// <summary>
/// Checks if any of the given tags have been added.
/// </summary>
/// <param name="tags">The tags to check for.</param>
/// <returns>true if any of them exist, false otherwise.</returns>
public bool HasAnyTag(IEnumerable<string> tags)
{
return _tags.Overlaps(tags);
}

/// <summary>
/// Tries to remove a tag if it exists.
/// </summary>
/// <param name="tag">The tag to remove.</param>
/// <returns>true if it was removed, false if it didn't exist.</returns>
public bool RemoveTag(string tag)
{
return _tags.Remove(tag);
}

/// <summary>
/// Tries to remove all of the given tags if they exist.
/// </summary>
/// <param name="tags">The tags to remove.</param>
/// <returns>true if any tag was removed, false otherwise.</returns>
public bool RemoveTags(params string[] tags)
{
return RemoveTags(tags.AsEnumerable());
}

/// <summary>
/// Tries to remove all of the given tags if they exist.
/// </summary>
/// <param name="tags">The tags to remove.</param>
/// <returns>true if any tag was removed, false otherwise.</returns>
public bool RemoveTags(IEnumerable<string> tags)
{
var count = _tags.Count;

_tags.ExceptWith(tags);

return _tags.Count < count;
}
}
}