Add Label class
ADD
WalletWasabi.Tests/UnitTests/LabelTests.cs
+using System;
+using System.Collections.Generic;
+using System.Text;
+using WalletWasabi.Models;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests
+{
+ public class LabelTests
+ {
+ [Fact]
+ public void LabelParsingTests()
+ {
+ var label = new Label();
+ Assert.Equal("", label.ToString());
+
+ label = new Label("");
+ Assert.Equal("", label.ToString());
+
+ label = new Label(null);
+ Assert.Equal("", label.ToString());
+
+ label = new Label(" ");
+ Assert.Equal("", label.ToString());
+
+ label = new Label(",");
+ Assert.Equal("", label.ToString());
+
+ label = new Label(":");
+ Assert.Equal("", label.ToString());
+
+ label = new Label("foo");
+ Assert.Equal("foo", label.ToString());
+
+ label = new Label("foo", "bar");
+ Assert.Equal("bar, foo", label.ToString());
+
+ label = new Label("foo bar");
+ Assert.Equal("foo bar", label.ToString());
+
+ label = new Label("foo bar", "Buz quX@");
+ Assert.Equal("Buz quX@, foo bar", label.ToString());
+
+ label = new Label(new List<string>() { "foo", "bar" });
+ Assert.Equal("bar, foo", label.ToString());
+
+ label = new Label(" foo ");
+ Assert.Equal("foo", label.ToString());
+
+ label = new Label("foo ", " bar");
+ Assert.Equal("bar, foo", label.ToString());
+
+ label = new Label(new List<string>() { " foo ", " bar " });
+ Assert.Equal("bar, foo", label.ToString());
+
+ label = new Label(new List<string>() { "foo:", ":bar", null, ":buz:", ",", ": , :", "qux:quux", "corge,grault", "", " ", " , garply, waldo,", " : , : , fred , : , : plugh, : , : ," });
+ Assert.Equal("bar, buz, corge, foo, fred, garply, grault, plugh, quux, qux, waldo", label.ToString());
+
+ label = new Label(",: foo::bar :buz:,: , :qux:quux, corge,grault , garply, waldo, : , : , fred , : , : plugh, : , : ,");
+ Assert.Equal("bar, buz, corge, foo, fred, garply, grault, plugh, quux, qux, waldo", label.ToString());
+ }
+
+ [Fact]
+ public void LabelEqualityTests()
+ {
+ var label = new Label("foo");
+ var label2 = new Label(label.ToString());
+ Assert.Equal(label, label2);
+
+ label = new Label("foo, bar, buz");
+ label2 = new Label(label.ToString());
+ Assert.Equal(label, label2);
+
+ label2 = new Label("bar, buz, foo");
+ Assert.Equal(label, label2);
+
+ var label3 = new Label("bar, buz");
+ Assert.NotEqual(label, label3);
+
+ Label label4 = null;
+ Label label5 = null;
+ Assert.Equal(label4, label5);
+ Assert.NotEqual(label, label4);
+ Assert.False(label.Equals(label4));
+ Assert.False(label == label4);
+ }
+
+ [Fact]
+ public void SpecialLabelTests()
+ {
+ var label = new Label("");
+ Assert.Equal(label, Label.Empty);
+ Assert.True(label.IsEmpty);
+ }
+ }
+}

ADD
WalletWasabi/Models/Label.cs
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WalletWasabi.Models
+{
+ public class Label : IEquatable<Label>
+ {
+ public static Label Empty { get; } = new Label();
+ public static char[] Separators { get; } = new[] { ',', ':' };
+ public IEnumerable<string> Labels { get; }
+ public bool IsEmpty { get; }
+
+ public Label(IEnumerable<string> labels) : this(labels?.ToArray())
+ {
+ }
+
+ public Label(params string[] labels)
+ {
+ Labels = (labels
+ ?.SelectMany(x => x?.Split(Separators, StringSplitOptions.RemoveEmptyEntries) ?? new string[0])
+ ?.Select(x => x.Trim())
+ ?.Where(x => x != "")
+ ?.OrderBy(x => x)
+ ?? Enumerable.Empty<string>())
+ .ToArray();
+
+ HashCode = ((IStructuralEquatable)Labels).GetHashCode(EqualityComparer<string>.Default);
+ IsEmpty = !Labels.Any();
+ }
+
+ public override string ToString()
+ {
+ return IsEmpty ? "" : string.Join(", ", Labels);
+ }
+
+ #region Equality
+
+ public override bool Equals(object obj) => obj is Label label && this == label;
+
+ public bool Equals(Label other) => this == other;
+
+ private int HashCode { get; }
+
+ public override int GetHashCode() => HashCode;
+
+ public static bool operator ==(Label x, Label y)
+ {
+ if (x is null)
+ {
+ if (y is null)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (y is null)
+ {
+ return false;
+ }
+ else
+ {
+ return x.Labels.SequenceEqual(y.Labels);
+ }
+ }
+ }
+
+ public static bool operator !=(Label x, Label y) => !(x == y);
+
+ #endregion Equality
+ }
+}

Add Label class