LibVLCAPICoverage.cs 5.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
using LibVLCSharp.Shared;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;

namespace LibVLCSharp.Tests
{
    [TestFixture]
    public class LibVLCAPICoverage
    {
        const string LibVLCSym3URL = "https://raw.githubusercontent.com/videolan/vlc-3.0/3.0.0/lib/libvlc.sym";
        const string LibVLCDeprecatedSymUrl = "https://raw.githubusercontent.com/videolan/vlc-3.0/master/include/vlc/deprecated.h";

        [Test]
        public async Task CheckLibVLCCoverage()
        {
            var symPath = Path.GetTempFileName();
            var deprecatedSymPath = Path.GetTempFileName();

            using (var client = new WebClient())
            {                
                client.DownloadFile(LibVLCSym3URL, symPath);
                client.DownloadFile(LibVLCDeprecatedSymUrl, deprecatedSymPath);
            }
            
            List<string> dllImports = new List<string>();

            var eventManager = typeof(MediaPlayer).GetRuntimeProperties()
                .FirstOrDefault(n => n.Name.EndsWith("EventManager"))
                .PropertyType
                .BaseType;

            List<Type> libvlcTypes = new List<Type>
            {
                typeof(LibVLC),
                typeof(MediaPlayer),
                typeof(Media),
                typeof(MediaDiscoverer),
                typeof(RendererDiscoverer),
                typeof(RendererItem),
                typeof(Dialog),
                typeof(MediaList),
                typeof(Equalizer),
                eventManager
            };

            var deprecatedSymbolsLine = new List<string>();

            var deprecatedSymFileLines = await File.ReadAllLinesAsync(deprecatedSymPath);
            for (var i = 0; i < deprecatedSymFileLines.Count(); i++)
            {
                var currentLine = deprecatedSymFileLines[i];
                if(currentLine.StartsWith("LIBVLC_DEPRECATED"))
                {
                    deprecatedSymbolsLine.Add(deprecatedSymFileLines[i + 1]);
                }
            }

            var deprecatedSymbols = new List<string>();

            foreach (var symLine in deprecatedSymbolsLine)
            {
                var libvlcIndexStart = symLine.IndexOf("libvlc");
                var sym1 = symLine.Substring(libvlcIndexStart);
                var finalSymbol = new string(sym1.TakeWhile(c => c != '(').ToArray());
                if(finalSymbol.Contains('*'))
                {
                    finalSymbol = finalSymbol.Substring(finalSymbol.IndexOf('*') + 1);
                }
                
                deprecatedSymbols.Add(finalSymbol.Trim());
            }

            List<string> implementedButHidden = new List<string>
            {
                "libvlc_media_player_set_android_context", // android build only
                "libvlc_free" // hidden in internal type
            };

            List<string> internalSymbolsThatShouldNotBeThere = new List<string>
            {
                "libvlc_get_input_thread", "libvlc_media_new_from_input_item", "libvlc_media_set_state"
            };

            List<string> NotGonnaImplementYetUntilActualUserDemandIfItMakesSense = new List<string>
            {
                "libvlc_printerr", "libvlc_vprinterr", "libvlc_clock", "libvlc_dialog_get_context", "libvlc_dialog_set_context",
                "libvlc_event_type_name", "libvlc_log_get_object", "libvlc_vlm", "libvlc_media_list_player", "libvlc_media_library"
            };

            List<string> exclude = new List<string>();
            exclude.AddRange(implementedButHidden);
            exclude.AddRange(internalSymbolsThatShouldNotBeThere);
            exclude.AddRange(NotGonnaImplementYetUntilActualUserDemandIfItMakesSense);

            foreach (var libvlcType in libvlcTypes)
            {
                var r = libvlcType.GetNestedType("Native", BindingFlags.NonPublic);
                if (r == null) continue;

                foreach (var method in r.GetRuntimeMethods())
                {
                    foreach (var attr in method.CustomAttributes)
                    {
                        if (attr.AttributeType.Name.Equals("DllImportAttribute"))
                        {
                            var arg = attr.NamedArguments.FirstOrDefault(a => a.MemberName.Equals("EntryPoint"));
                            if (arg == null) continue;

                            var sym = (string)arg.TypedValue.Value;

                            dllImports.Add(sym);
                        }
                    }
                }
            }

            bool ShouldExclude(string symbol)
            {
                foreach(var excludeSymbol in exclude)
                {
                    if (symbol.StartsWith(excludeSymbol))
                        return true;
                }
                return false;
            }

            Debug.WriteLine($"we have {dllImports.Count} dll import statements");

            List<string> libvlcSymFile = new List<string>();
            foreach(var sym in File.ReadLines(symPath))
            {
                if (ShouldExclude(sym)) continue;

                libvlcSymFile.Add(sym);
            }

            var missingApis = libvlcSymFile
                .Except(dllImports)
                .Except(deprecatedSymbols)
                .ToList();

            Debug.WriteLine($"{missingApis.Count} missing APIs implementation");
            foreach(var miss in missingApis)
            {
                Debug.WriteLine(miss);
            }
            Debug.WriteLine($"libvlc 3.0 has {libvlcSymFile.Count} public APIs symbols");
            // libvlc_event_detach
            Assert.AreEqual(dllImports.Count, libvlcSymFile.Count);
        }
    }
}