diff --git a/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs b/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs index 0d47d4f0a3..19a8d46d46 100644 --- a/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs +++ b/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs @@ -27,7 +27,27 @@ public sealed class ClangScraper /// Placeholder used in place of library paths /// public static readonly string LibraryNamespacePlaceholder = "LIBRARY_NAMESPACE"; - + + /// + /// Scrapes the given XML document for symbols + /// + /// A XML Document, the format is assumed to be similar to what ClangSharp would output. + /// Any number of symbols scraped from the given xml + public IEnumerable ScrapeXML(XmlDocument document) + { + var bindings = document.ChildNodes.Cast().FirstOrDefault(x => x.LocalName == "bindings" && x is XmlElement) as XmlElement; + + if (bindings is null) + { + return Enumerable.Empty(); + } + + var visitor = new XmlVisitor(); + visitor.Visit(bindings); + + return visitor.Symbols; + } + /// /// Calls into Clang to generate XML used to scrape symbols. /// diff --git a/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs b/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs new file mode 100644 index 0000000000..8223cdf0a6 --- /dev/null +++ b/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using Silk.NET.SilkTouch.Symbols; + +namespace Silk.NET.SilkTouch.Scraper; + +internal sealed class XmlVisitor +{ + private List _symbols = new(); + + public IEnumerable Symbols => _symbols; + + public void Visit(XmlNode node) + { + switch (node) + { + case XmlElement { Name: "bindings" } bindings: + { + foreach (var child in bindings.ChildNodes.Cast()) + { + if (child is null) continue; + Visit(child); + } + break; + } + default: + { + throw new NotImplementedException(); + } + } + } +} diff --git a/tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs b/tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs index ba620dea86..fc4157d79f 100644 --- a/tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs +++ b/tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs @@ -29,7 +29,7 @@ public void FieldIsPublic() ( new FieldSymbol ( - new StructSymbol(new IdentifierSymbol("int"), ImmutableArray.Empty), + new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty), new IdentifierSymbol("Test") ) ) as FieldDeclarationSyntax; @@ -45,7 +45,7 @@ public void FieldHasCorrectTypeIdentifier() ( new FieldSymbol ( - new StructSymbol(new IdentifierSymbol("int"), ImmutableArray.Empty), + new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty), new IdentifierSymbol("Test") ) ) as FieldDeclarationSyntax; @@ -63,7 +63,7 @@ public void FieldHasCorrectIdentifier() ( new FieldSymbol ( - new StructSymbol(new IdentifierSymbol("int"), ImmutableArray.Empty), + new StructSymbol(new IdentifierSymbol("int"), StructLayout.Empty), new IdentifierSymbol("Test") ) ) as FieldDeclarationSyntax; diff --git a/tests/Silk.NET.SilkTouch.Scraper.Tests/BasicXMLTests.cs b/tests/Silk.NET.SilkTouch.Scraper.Tests/BasicXMLTests.cs new file mode 100644 index 0000000000..679d3e5cc9 --- /dev/null +++ b/tests/Silk.NET.SilkTouch.Scraper.Tests/BasicXMLTests.cs @@ -0,0 +1,140 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Loader; +using System.Xml; +using Xunit; + +namespace Silk.NET.SilkTouch.Scraper.Tests; + +public class BasicXMLTests +{ + /* + * NOTE: + * MOST OF THE FUNCTIONALITY TESTED HERE REALLY DEPENDS ON CLANG(SHARP). + * THEREFORE IT IS UNNECESSARY TO TEST IT AS DETAILED AS OTHER PARTS OF THIS SYSTEM. + * ONLY CREATE TESTS HERE IF THERE IS AN ISSUE IN OUR SYSTEM THAT YOU NEED TO TRACK DOWN + * DO NOT JUST CREATE TESTS TO TEST CLANGSHARP. + * IF THERE ARE ISSUES WITH THE XML NOT REFLECTING PART OF A HEADER: + * 1. CHECK OUR CONFIGURATION. ITS FAIRLY SIMPLE AND BAREBONES. + * 2. IF 1. DID NOT RESOLVE THE PROBLEM, RAISE WITH CLANGSHARP/CLANG INSTEAD. + * WE DO NOT WANT TO REWRITE THE XML IN ANY WAY. + */ + + + private const string TempFileHeader = @"/* This file is temporarily created for use by Silk.NET tests. If you don't intend to run such a test, feel free to delete this file. */"; + + + [Fact] + public void BasicStructScrapingTest() + { + var tempFile = Path.GetTempFileName(); + + File.WriteAllText(tempFile, TempFileHeader + @" +#include + +typedef struct { + int32_t f1; + int32_t f2; +} Test;"); + + var scraper = new ClangScraper(); + var xml = scraper.GenerateXML + (tempFile, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()); + + /* + Next, Assert the XML looks something like this: + + + + + + int + + + int + + + + + */ + + Assert.NotNull(xml); + // Root + Assert.Collection(xml!.ChildNodes.Cast(), + static dec => Assert.IsType(dec), // Top Declaration + static bindings => // Root Bindings Element + { + var e = Assert.IsType(bindings); + Assert.Equal("bindings", e.LocalName); + Assert.Collection(e.ChildNodes.Cast(), // namespaces + static @namespace => + { + var e = Assert.IsType(@namespace); + var nameAtt = e.Attributes["name"]; + Assert.NotNull(nameAtt); + Assert.Equal(ClangScraper.LibraryNamespacePlaceholder, nameAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // namespace members + static @struct => + { + var e = Assert.IsType(@struct); + var nameAtt = e.Attributes["name"]; + Assert.NotNull(nameAtt); + Assert.Equal("Test", nameAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // struct members + static field => + { + var e = Assert.IsType(field); + var nameAtt = e.Attributes["name"]; + Assert.NotNull(nameAtt); + Assert.Equal("f1", nameAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // field infos + static type => + { + var e = Assert.IsType(type); + var nativeAtt = e.Attributes["native"]; + Assert.NotNull(nativeAtt); + Assert.Equal("int32_t", nativeAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // unwrap converted type + static type => + { + var e = Assert.IsType(type); + Assert.Equal("int", e.Value); + }); + }); + }, static field => + { + var e = Assert.IsType(field); + var nameAtt = e.Attributes["name"]; + Assert.NotNull(nameAtt); + Assert.Equal("f2", nameAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // field infos + static type => + { + var e = Assert.IsType(type); + var nativeAtt = e.Attributes["native"]; + Assert.NotNull(nativeAtt); + Assert.Equal("int32_t", nativeAtt!.Value); + + Assert.Collection(e.ChildNodes.Cast(), // unwrap converted type + static type => + { + var e = Assert.IsType(type); + Assert.Equal("int", e.Value); + }); + }); + }); + }); + }); + }); + } +} diff --git a/tests/Silk.NET.SilkTouch.Scraper.Tests/IdentityScrapingTests.cs b/tests/Silk.NET.SilkTouch.Scraper.Tests/IdentityScrapingTests.cs new file mode 100644 index 0000000000..c090c63e27 --- /dev/null +++ b/tests/Silk.NET.SilkTouch.Scraper.Tests/IdentityScrapingTests.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Xml; +using Xunit; + +namespace Silk.NET.SilkTouch.Scraper.Tests; + +public class IdentityScrapingTests +{ + [Fact] + public void EmptyXmlGeneratesNoSymbols() + { + var doc = new XmlDocument(); + + var symbols = new ClangScraper().ScrapeXML(doc); + + Assert.Empty(symbols); + } + + [Fact] + public void EmptyBindingsXmlGeneratesNoSymbols() + { + var doc = new XmlDocument(); + doc.LoadXml(@" + +"); + + var symbols = new ClangScraper().ScrapeXML(doc); + + Assert.Empty(symbols); + } +} + diff --git a/tests/Silk.NET.SilkTouch.Scraper.Tests/StructScrapingTests.cs b/tests/Silk.NET.SilkTouch.Scraper.Tests/StructScrapingTests.cs index 0982cbb572..05ad8c4617 100644 --- a/tests/Silk.NET.SilkTouch.Scraper.Tests/StructScrapingTests.cs +++ b/tests/Silk.NET.SilkTouch.Scraper.Tests/StructScrapingTests.cs @@ -1,127 +1,15 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Loader; -using System.Xml; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using Xunit; namespace Silk.NET.SilkTouch.Scraper.Tests; public class StructScrapingTests { - private const string TempFileHeader = @"/* This file is temporarily created for use by Silk.NET tests. If you don't intend to run such a test, feel free to delete this file. */"; - - [Fact] - public void BasicStructScrapingTest() + public void StructXMLGeneratesStructSymbol() { - var tempFile = Path.GetTempFileName(); - - File.WriteAllText(tempFile, TempFileHeader + @" -#include - -typedef struct { - int32_t f1; - int32_t f2; -} Test;"); - - var scraper = new ClangScraper(); - var xml = scraper.GenerateXML - (tempFile, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()); - - /* - Next, Assert the XML looks something like this: - - - - - - int - - - int - - - - - */ - Assert.NotNull(xml); - // Root - Assert.Collection(xml!.ChildNodes.Cast(), - static dec => Assert.IsType(dec), // Top Declaration - static bindings => // Root Bindings Element - { - var e = Assert.IsType(bindings); - Assert.Equal("bindings", e.LocalName); - Assert.Collection(e.ChildNodes.Cast(), // namespaces - static @namespace => - { - var e = Assert.IsType(@namespace); - var nameAtt = e.Attributes["name"]; - Assert.NotNull(nameAtt); - Assert.Equal(ClangScraper.LibraryNamespacePlaceholder, nameAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // namespace members - static @struct => - { - var e = Assert.IsType(@struct); - var nameAtt = e.Attributes["name"]; - Assert.NotNull(nameAtt); - Assert.Equal("Test", nameAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // struct members - static field => - { - var e = Assert.IsType(field); - var nameAtt = e.Attributes["name"]; - Assert.NotNull(nameAtt); - Assert.Equal("f1", nameAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // field infos - static type => - { - var e = Assert.IsType(type); - var nativeAtt = e.Attributes["native"]; - Assert.NotNull(nativeAtt); - Assert.Equal("int32_t", nativeAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // unwrap converted type - static type => - { - var e = Assert.IsType(type); - Assert.Equal("int", e.Value); - }); - }); - }, static field => - { - var e = Assert.IsType(field); - var nameAtt = e.Attributes["name"]; - Assert.NotNull(nameAtt); - Assert.Equal("f2", nameAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // field infos - static type => - { - var e = Assert.IsType(type); - var nativeAtt = e.Attributes["native"]; - Assert.NotNull(nativeAtt); - Assert.Equal("int32_t", nativeAtt!.Value); - - Assert.Collection(e.ChildNodes.Cast(), // unwrap converted type - static type => - { - var e = Assert.IsType(type); - Assert.Equal("int", e.Value); - }); - }); - }); - }); - }); - }); } }