﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.DynamicProxy.Internal;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Text.Classification;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
{
    [UseExportProvider]
    public class ClassificationTypeNamesTests
    {
        public static IEnumerable<object[]> AllPublicClassificationTypeNames
        {
            get
            {
                foreach (var field in typeof(ClassificationTypeNames).GetFields(BindingFlags.Static | BindingFlags.Public))
                {
                    yield return new object[] { field.Name, field.GetRawConstantValue() };
                }
            }
        }
        public static IEnumerable<object[]> AllClassificationTypeNames => typeof(ClassificationTypeNames).GetAllFields().Where(
            field => field.GetValue(null) is string value).Select(field => new object[] { (string)field.GetValue(null) });

        [Theory]
        [MemberData(nameof(AllPublicClassificationTypeNames))]
        [WorkItem("https://github.com/dotnet/roslyn/issues/25716")]
        public void ClassificationTypeExported(string fieldName, object constantValue)
        {
            var classificationTypeName = Assert.IsType<string>(constantValue);
            var exportProvider = EditorTestCompositions.EditorFeatures.ExportProviderFactory.CreateExportProvider();
            var classificationTypeRegistryService = exportProvider.GetExport<IClassificationTypeRegistryService>().Value;
            var classificationType = classificationTypeRegistryService.GetClassificationType(classificationTypeName);
            Assert.True(classificationType != null, $"{nameof(ClassificationTypeNames)}.{fieldName} has value \"{classificationTypeName}\", but no matching {nameof(ClassificationTypeDefinition)} was exported.");
        }

        [Theory, MemberData(nameof(AllClassificationTypeNames))]
        public void AllTypeNamesContainsAllClassifications(string fieldName)
            => Assert.True(ClassificationTypeNames.AllTypeNames.Contains(fieldName), $"Missing token type {fieldName}.");

        [Fact]
        public void AllTypeNamesContainsNoDuplicates()
            => Assert.Equal(ClassificationTypeNames.AllTypeNames.Distinct(), ClassificationTypeNames.AllTypeNames);
    }
}
