/// <summary>
        /// Removes the specified tags from the set returning a new set.
        /// </summary>
        /// <param name="left">The set to remove the specified tags from.</param>
        /// <param name="right">Tags to remove from the set.</param>
        /// <returns>The resulting set.</returns>
        public static TagSet operator -(TagSet left, IEnumerable <string> right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }
            foreach (string tag in right)
            {
                LogWriterTag.CheckTag(tag);
            }

            var newSet = new HashSet <string>(left, StringComparer.Ordinal);

            newSet.ExceptWith(right);
            if (newSet.Count == left.Count)
            {
                return(left);
            }
            var tags = new List <string>(newSet);

            return(new TagSet(tags));
        }
        public void CheckTag_Invalid()
        {
            var builder = new StringBuilder();
            var random  = new Random(0);

            for (int sample = 0; sample < 10000; sample++)
            {
                builder.Clear();

                // generate a valid tag
                int length = random.Next(1, 50);
                for (int i = 0; i < length; i++)
                {
                    int j = random.Next(0, ValidCharSet.Length - 1);
                    builder.Append(ValidCharSet[j]);
                }

                // find a character that is not valid and inject it into the tag
                char c;
                do
                {
                    c = (char)random.Next(0, 65535);
                } while (ValidCharSet.Contains(c));

                int index = random.Next(0, builder.Length - 1);
                builder.Insert(index, c);

                // check the tag
                string tag = builder.ToString();
                Assert.Throws <ArgumentException>(() => LogWriterTag.CheckTag(tag));
            }
        }
        /// <summary>
        /// Adds the specified tag to the set returning a new set.
        /// </summary>
        /// <param name="left">The set to add the specified tag to.</param>
        /// <param name="right">Tag to add to the set.</param>
        /// <returns>The resulting set.</returns>
        public static TagSet operator +(TagSet left, string right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }
            LogWriterTag.CheckTag(right);

            var newSet = new HashSet <string>(left, StringComparer.Ordinal)
            {
                right
            };

            if (newSet.Count == left.Count)
            {
                return(left);
            }
            var tags = new List <string>(newSet);

            return(new TagSet(tags));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="TagSet"/> class with the specified tags.
 /// </summary>
 /// <param name="tags">Tags to keep in the collection.</param>
 /// <exception cref="ArgumentException">At least one of the tags is invalid.</exception>
 public TagSet(IEnumerable <string> tags)
 {
     if (tags == null)
     {
         throw new ArgumentNullException(nameof(tags));
     }
     foreach (string tag in tags)
     {
         LogWriterTag.CheckTag(tag);
     }
     mTags = new List <string>(new HashSet <string>(tags, StringComparer.Ordinal));
     mTags.Sort(StringComparer.OrdinalIgnoreCase);
     mHashCode = CalculateHashCode(mTags);
 }
        public void CheckTag_Valid()
        {
            var builder = new StringBuilder();
            var random  = new Random(0);

            for (int sample = 0; sample < 10000; sample++)
            {
                builder.Clear();

                // generate a valid tag
                int length = random.Next(1, 50);
                for (int i = 0; i < length; i++)
                {
                    int j = random.Next(0, ValidCharSet.Length - 1);
                    builder.Append(ValidCharSet[j]);
                }

                // check the tag
                string tag = builder.ToString();
                LogWriterTag.CheckTag(tag);
            }
        }