File: System\Xaml\XamlNodeQueueTests.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\tests\UnitTests\System.Xaml.Tests\System.Xaml.Tests.csproj (System.Xaml.Tests)
// 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.
 
using System.Collections.Generic;
using System.Reflection;
using Xunit;
 
namespace System.Xaml.Tests;
 
public class XamlNodeQueueTests
{
    [Fact]
    public void Ctor_XamlSchemaContext()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        Assert.True(queue.IsEmpty);
        Assert.Equal(0, queue.Count);
    }
 
    [Fact]
    public void Ctor_NullSchemaContext_ThrowsArgumentNullException()
    {
        Assert.Throws<ArgumentNullException>("schemaContext", () => new XamlNodeQueue(null));
    }
 
    [Fact]
    public void Reader_GetProperties_ReturnsExpected()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        XamlReader reader = queue.Reader;
        Assert.NotNull(reader);
        Assert.Same(reader, queue.Reader);
 
        Assert.Equal(XamlNodeType.None, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
        Assert.Equal(context, reader.SchemaContext);
    }
 
    [Fact]
    public void Reader_NotIXamlLineInfoReader_PropertiesReturnExpected()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        IXamlLineInfo reader = Assert.IsAssignableFrom<IXamlLineInfo>(queue.Reader);
        Assert.False(reader.HasLineInfo);
        Assert.Equal(0, reader.LineNumber);
        Assert.Equal(0, reader.LinePosition);
    }
 
    [Fact]
    public void Reader_ReadWhenEmpty_SetsEof()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        XamlReader reader = queue.Reader;
        Assert.False(reader.Read());
        Assert.Equal(0, queue.Count);
        
        Assert.Equal(XamlNodeType.None, reader.NodeType);
        Assert.True(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
 
    [Fact]
    public void Reader_ReadWhenDisposed_ThrowsObjectDisposedException()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        XamlReader reader = queue.Reader;
        reader.Close();
 
        Assert.Throws<ObjectDisposedException>(() => reader.Read());
    }
 
    [Fact]
    public void Writer_Get_ReturnsExpected()
    {
        var context = new XamlSchemaContext();
        var queue = new XamlNodeQueue(context);
        XamlWriter writer = queue.Writer;
        Assert.NotNull(writer);
        Assert.Same(writer, queue.Writer);
    }
 
    [Fact]
    public void Writer_WriteGetObject_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteGetObject();
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.GetObject, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
 
    [Fact]
    public void Writer_WriteGetObjectWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteGetObject());
    }
 
#if !DEBUG // This triggers a Debug.Assert.
    public static IEnumerable<object?[]> Writer_WriteStartObject_TestData()
    {
        yield return new object?[] { XamlLanguage.Object };
        yield return new object?[] { null };
    }
 
    [Theory]
    [MemberData(nameof(Writer_WriteStartObject_TestData))]
    public void Writer_WriteStartObject_Success(XamlType type)
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteStartObject(type);
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.StartObject, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Equal(type, reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
#endif
 
    [Fact]
    public void Writer_WriteStartObjectWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteStartObject(null));
    }
 
    [Fact]
    public void Writer_WriteEndObject_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteEndObject();
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.EndObject, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
 
    [Fact]
    public void Writer_WriteEndObjectWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteEndObject());
    }
 
#if !DEBUG // This triggers a Debug.Assert.
    public static IEnumerable<object?[]> Writer_WriteStartMember_TestData()
    {
        yield return new object?[] { XamlLanguage.Key };
        yield return new object?[] { null };
    }
 
    [Theory]
    [MemberData(nameof(Writer_WriteStartMember_TestData))]
    public void Writer_WriteStartMember_Success(XamlMember member)
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteStartMember(member);
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.StartMember, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Equal(member, reader.Member);
    }
#endif
 
    [Fact]
    public void Writer_WriteStartMemberWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteStartMember(null));
    }
 
    [Fact]
    public void Writer_WriteEndMember_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteEndMember();
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.EndMember, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
 
    [Fact]
    public void Writer_WriteEndMemberWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteEndMember());
    }
 
    public static IEnumerable<object?[]> Writer_WriteValue_TestData()
    {
        yield return new object?[] { 1 };
        yield return new object?[] { null };
    }
 
    [Theory]
    [MemberData(nameof(Writer_WriteValue_TestData))]
    public void Writer_WriteValue_Success(object value)
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteValue(value);
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.Value, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Null(reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Equal(value, reader.Value);
        Assert.Null(reader.Member);
    }
 
    [Fact]
    public void Writer_WriteValueWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteValue(null));
    }
 
#if !DEBUG // This triggers a Debug.Assert.
    public static IEnumerable<object?[]> Writer_WriteNamespace_TestData()
    {
        yield return new object?[] { new NamespaceDeclaration("namespace", "prefix") };
        yield return new object?[] { null };
    }
 
    [Theory]
    [MemberData(nameof(Writer_WriteNamespace_TestData))]
    public void Writer_WriteNamespace_Success(NamespaceDeclaration namespaceDeclaration)
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.WriteNamespace(namespaceDeclaration);
        Assert.Equal(1, queue.Count);
 
        XamlReader reader = queue.Reader;
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.NamespaceDeclaration, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Equal(namespaceDeclaration, reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
    }
#endif
 
    [Fact]
    public void Writer_WriteNamespaceWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        Assert.Throws<ObjectDisposedException>(() => writer.WriteNamespace(null));
    }
 
    [Fact]
    public void Writer_SetLineInfoBeforeWrite_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        var namespaceDeclaration = new NamespaceDeclaration("namespace", "prefix");
        consumer.SetLineInfo(1, 2);
        writer.WriteNamespace(namespaceDeclaration);
        Assert.Equal(2, queue.Count);
 
        XamlReader reader = queue.Reader;
        IXamlLineInfo lineInfo = Assert.IsAssignableFrom<IXamlLineInfo>(reader);
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
 
        Assert.True(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.NamespaceDeclaration, reader.NodeType);
        Assert.False(reader.IsEof);
        Assert.Equal(namespaceDeclaration, reader.Namespace);
        Assert.Null(reader.Type);
        Assert.Null(reader.Value);
        Assert.Null(reader.Member);
 
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(1, lineInfo.LineNumber);
        Assert.Equal(2, lineInfo.LinePosition);
    }
 
    [Fact]
    public void Writer_SetLineInfoAfterWrite_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        var namespaceDeclaration = new NamespaceDeclaration("namespace", "prefix");
        writer.WriteNamespace(namespaceDeclaration);
        consumer.SetLineInfo(1, 2);
        Assert.Equal(2, queue.Count);
 
        XamlReader reader = queue.Reader;
        IXamlLineInfo lineInfo = Assert.IsAssignableFrom<IXamlLineInfo>(reader);
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
 
        Assert.True(reader.Read());
        Assert.Equal(1, queue.Count);
        Assert.Equal(XamlNodeType.NamespaceDeclaration, reader.NodeType);
 
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
    }
 
    [Fact]
    public void Writer_SetLineInfoMultipleTimes_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        consumer.SetLineInfo(1, 2);
        consumer.SetLineInfo(2, 3);
        Assert.Equal(2, queue.Count);
 
        XamlReader reader = queue.Reader;
        IXamlLineInfo lineInfo = Assert.IsAssignableFrom<IXamlLineInfo>(reader);
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
 
        Assert.False(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.None, reader.NodeType);
 
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(2, lineInfo.LineNumber);
        Assert.Equal(3, lineInfo.LinePosition);
    }
 
    [Fact]
    public void Writer_SetLineInfoMultipleTimesAfterGettingReader_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        XamlReader reader = queue.Reader;
        IXamlLineInfo lineInfo = Assert.IsAssignableFrom<IXamlLineInfo>(reader);
        Assert.False(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
 
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        consumer.SetLineInfo(1, 2);
        consumer.SetLineInfo(2, 3);
        Assert.Equal(2, queue.Count);
 
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(0, lineInfo.LineNumber);
        Assert.Equal(0, lineInfo.LinePosition);
 
        Assert.False(reader.Read());
        Assert.Equal(0, queue.Count);
        Assert.Equal(XamlNodeType.None, reader.NodeType);
 
        Assert.True(lineInfo.HasLineInfo);
        Assert.Equal(2, lineInfo.LineNumber);
        Assert.Equal(3, lineInfo.LinePosition);
    }
 
    [Fact]
    public void Writer_SetLineInfoWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        Assert.Throws<ObjectDisposedException>(() => consumer.SetLineInfo(1, 2));
    }
 
    [Fact]
    public void Writer_GetShouldProvideLineInfo_ReturnTrue()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(queue.Writer);
        Assert.True(consumer.ShouldProvideLineInfo);
    }
 
    [Fact]
    public void Writer_GetShouldProvideLineInfoWhenDisposed_ThrowsObjectDisposedException()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        Assert.Throws<ObjectDisposedException>(() => consumer.ShouldProvideLineInfo);
    }
 
    [Fact]
    public void Writer_CloseMultipleTimes_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
        writer.Close();
 
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        Assert.Throws<ObjectDisposedException>(() => consumer.ShouldProvideLineInfo);
    }
 
    [Fact]
    public void Writer_DisposeDisposingFalse_Success()
    {
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        MethodInfo dispose = writer.GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.NonPublic)!;
        dispose.Invoke(writer, new object[] { false });
 
        IXamlLineInfoConsumer consumer = Assert.IsAssignableFrom<IXamlLineInfoConsumer>(writer);
        Assert.Throws<ObjectDisposedException>(() => consumer.ShouldProvideLineInfo);
    }
 
    [Fact]
    public void Writer_DisposeCallAddDelegate_ThrowsXamlException()
    {
        // Dead code in WriterDelegate.
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        FieldInfo addDelegateField = writer.GetType().GetField("_addDelegate", BindingFlags.Instance | BindingFlags.NonPublic)!;
        Delegate addDelegate = Assert.IsAssignableFrom<Delegate>(addDelegateField.GetValue(writer));
 
        bool threwXamlException = true;
        try
        {
            addDelegate.DynamicInvoke(new object?[] { null, null });
        }
        catch (TargetInvocationException ex) when (ex.InnerException is XamlException)
        {
            threwXamlException = true;
        }
        Assert.True(threwXamlException);
    }
 
    [Fact]
    public void Writer_DisposeCallAddLineInfoDelegate_ThrowsXamlException()
    {
        // Dead code in WriterDelegate.
        var queue = new XamlNodeQueue(new XamlSchemaContext());
        XamlWriter writer = queue.Writer;
        writer.Close();
 
        FieldInfo addLineInfoDelegateField = writer.GetType().GetField("_addLineInfoDelegate", BindingFlags.Instance | BindingFlags.NonPublic)!;
        Delegate addLineInfoDelegate = Assert.IsAssignableFrom<Delegate>(addLineInfoDelegateField.GetValue(writer));
 
        bool threwXamlException = true;
        try
        {
            addLineInfoDelegate.DynamicInvoke(new object?[] { null, null });
        }
        catch (TargetInvocationException ex) when (ex.InnerException is XamlException)
        {
            threwXamlException = true;
        }
        Assert.True(threwXamlException);
    }
 
    private delegate void XamlNodeAddDelegate(XamlNodeType nodeType, object data);
    private delegate void XamlLineInfoAddDelegate(int lineNumber, int linePosition);
}