Skip to content

Commit

Permalink
Merge pull request serilog#778 from adamchester/capturing-tests
Browse files Browse the repository at this point in the history
Cover property capturing with better tests
  • Loading branch information
nblumhardt authored Jun 19, 2016
2 parents 81ba6b3 + cee46e7 commit b758729
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 0 deletions.
112 changes: 112 additions & 0 deletions test/Serilog.Tests/Core/LogEventPropertyCapturingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using Serilog.Core;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Parameters;
using Serilog.Parsing;
using Serilog.Tests.Support;
using Xunit;

namespace Serilog.Tests.Core
{
public class LogEventPropertyCapturingTests
{
[Fact]
public void CapturingANamedScalarStringWorks()
{
Assert.Equal(
new[] { new LogEventProperty("who", new ScalarValue("world")) },
Capture("Hello {who}", "world"),
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void CapturingAPositionalScalarStringWorks()
{
Assert.Equal(
new[] { new LogEventProperty("0", new ScalarValue("world")) },
Capture("Hello {0}", "world"),
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void CapturingMixedPositionalAndNamedScalarsWorksUsingNames()
{
Assert.Equal(new[]
{
new LogEventProperty("who", new ScalarValue("worldNamed")),
new LogEventProperty("0", new ScalarValue("worldPositional")),
},
Capture("Hello {who} {0} {0}", "worldNamed", "worldPositional"),
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void CapturingIntArrayAsScalarSequenceValuesWorks()
{
const string template = "Hello {sequence}";
var templateArguments = new[] { 1, 2, 3, };
var expected = new[] {
new LogEventProperty("sequence",
new SequenceValue(new[] {
new ScalarValue(1),
new ScalarValue(2),
new ScalarValue(3) })) };

Assert.Equal(expected, Capture(template, templateArguments),
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void CapturingDestructuredStringArrayAsScalarSequenceValuesWorks()
{
const string template = "Hello {@sequence}";
var templateArguments = new[] { "1", "2", "3", };
var expected = new[] {
new LogEventProperty("sequence",
new SequenceValue(new[] {
new ScalarValue("1"),
new ScalarValue("2"),
new ScalarValue("3") })) };

Assert.Equal(expected, Capture(template, new object[] { templateArguments }),
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void WillCaptureProvidedPositionalValuesEvenIfSomeAreMissing()
{
Assert.Equal(new[]
{
new LogEventProperty("0", new ScalarValue(0)),
new LogEventProperty("1", new ScalarValue(1)),
},
Capture("Hello {3} {2} {1} {0} nothing more", 0, 1), // missing {2} and {3}
new LogEventPropertyStructuralEqualityComparer());
}

[Fact]
public void WillCaptureProvidedNamedValuesEvenIfSomeAreMissing()
{
Assert.Equal(new[]
{
new LogEventProperty("who", new ScalarValue("who")),
new LogEventProperty("what", new ScalarValue("what")),
},
Capture("Hello {who} {what} {where}", "who", "what"), // missing "where"
new LogEventPropertyStructuralEqualityComparer());
}

static IEnumerable<LogEventProperty> Capture(string messageTemplate, params object[] properties)
{
var mt = new MessageTemplateParser().Parse(messageTemplate);
var binder = new PropertyBinder(
new PropertyValueConverter(10, Enumerable.Empty<Type>(), Enumerable.Empty<IDestructuringPolicy>()));
return binder.ConstructProperties(mt, properties);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Serilog.Events;

namespace Serilog.Tests.Support
{
class LogEventPropertyStructuralEqualityComparer : IEqualityComparer<LogEventProperty>
{
readonly IEqualityComparer<LogEventPropertyValue> _valueEqualityComparer;

public LogEventPropertyStructuralEqualityComparer(
IEqualityComparer<LogEventPropertyValue> valueEqualityComparer = null)
{
this._valueEqualityComparer =
valueEqualityComparer ?? new LogEventPropertyValueComparer(EqualityComparer<object>.Default);
}

public bool Equals(LogEventProperty x, LogEventProperty y)
{
if (x == null || y == null)
return false; // throw new Exception($"the comparer doesn't support nulls, x={x}, y={y}");

return x.Name == y.Name
&& _valueEqualityComparer.Equals(x.Value, y.Value);
}

public int GetHashCode(LogEventProperty obj)
{
return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using Serilog.Events;
using Xunit;

namespace Serilog.Tests.Support
{
public class LogEventPropertyStructuralEqualityComparerTests
{
[Fact]
public void HandlesNullAsNotEqual()
{
var sut = new LogEventPropertyStructuralEqualityComparer();
Assert.False(sut.Equals(null, new LogEventProperty("a", new ScalarValue(null))));
Assert.False(sut.Equals(new LogEventProperty("a", new ScalarValue(null)), null));
Assert.False(sut.Equals(null, null));
}

[Fact]
public void LogEventPropertyStructuralEqualityComparerWorksForSequences()
{
var intStringDoubleScalarArray =
new[] { new ScalarValue(1), new ScalarValue("2"), new ScalarValue(3.0), };

var intStringFloatScalarArray =
new[] { new ScalarValue("1"), new ScalarValue(2), new ScalarValue(3.0f), };

var sequenceOfScalarsIntStringDoubleA = new LogEventProperty("a", new SequenceValue(intStringDoubleScalarArray));

var sequenceOfScalarsIntStringDoubleAStructurallyEqual = new LogEventProperty("a",
new SequenceValue(new[] { new ScalarValue(1), new ScalarValue("2"), new ScalarValue(3.0), }));

var sequenceOfScalarsIntStringDoubleAStructurallyNotEqual = new LogEventProperty("a",
new SequenceValue(new [] { new ScalarValue(1), new ScalarValue("2"), new ScalarValue(3.1), }));

var sequenceOfScalarsIntStringFloatA = new LogEventProperty("a", new ScalarValue(intStringFloatScalarArray));

var sequenceOfScalarsIntStringDoubleB = new LogEventProperty("b", new SequenceValue(intStringDoubleScalarArray));

var sut = new LogEventPropertyStructuralEqualityComparer();

// Structurally equal
Assert.True(sut.Equals(sequenceOfScalarsIntStringDoubleA, sequenceOfScalarsIntStringDoubleAStructurallyEqual));

// Not equal due to having a different property name (but otherwise structurally equal)
Assert.False(sut.Equals(sequenceOfScalarsIntStringDoubleA, sequenceOfScalarsIntStringDoubleB));

// Structurally not equal because element 3 has a different value
Assert.False(sut.Equals(sequenceOfScalarsIntStringDoubleA, sequenceOfScalarsIntStringDoubleAStructurallyNotEqual));

// Strucrtually not equal because element 3 has a different underlying value and type
Assert.False(sut.Equals(sequenceOfScalarsIntStringDoubleA, sequenceOfScalarsIntStringFloatA));
}

[Fact]
public void LogEventPropertyStructuralEqualityComparerWorksForScalars()
{
var scalarStringA = new LogEventProperty("a", new ScalarValue("a"));
var scalarStringAStructurallyEqual = new LogEventProperty("a", new ScalarValue("a"));

var scalarStringB = new LogEventProperty("b", new ScalarValue("b"));
var scalarStringBStructurallyNotEqual = new LogEventProperty("b", new ScalarValue("notEqual"));

var scalarIntA1 = new LogEventProperty("a", new ScalarValue(1));
var scalarIntA1StructurallyEqual = new LogEventProperty("a", new ScalarValue(1));
var scalarIntA1DiffValueSameType = new LogEventProperty("a", new ScalarValue(0));
var scalarIntB1 = new LogEventProperty("b", new ScalarValue(1));

var guid1 = Guid.NewGuid();
var guid2 = Guid.NewGuid();
var scalarGuid1 = new LogEventProperty("1", new ScalarValue(guid1));
var scalarGuid1StructurallyEqual = new LogEventProperty("1", new ScalarValue(guid1));
var scalarGuid1StructurallyNotEqual = new LogEventProperty("1", new ScalarValue("notEqual"));
var scalarGuid2 = new LogEventProperty("2", new ScalarValue(guid2));

var sut = new LogEventPropertyStructuralEqualityComparer();

Assert.True(sut.Equals(scalarStringA, scalarStringAStructurallyEqual));
Assert.True(sut.Equals(scalarIntA1, scalarIntA1StructurallyEqual));
Assert.True(sut.Equals(scalarGuid1, scalarGuid1StructurallyEqual));

Assert.False(sut.Equals(scalarStringB, scalarStringBStructurallyNotEqual));
Assert.False(sut.Equals(scalarIntA1, scalarIntB1));
Assert.False(sut.Equals(scalarIntA1, scalarIntA1DiffValueSameType));

Assert.False(sut.Equals(scalarGuid1, scalarGuid2));
Assert.False(sut.Equals(scalarGuid1, scalarGuid1StructurallyNotEqual));
}
}
}
52 changes: 52 additions & 0 deletions test/Serilog.Tests/Support/LogEventPropertyValueComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Serilog.Events;

namespace Serilog.Tests.Support
{
class LogEventPropertyValueComparer : IEqualityComparer<LogEventPropertyValue>
{
readonly IEqualityComparer<object> _objectEqualityComparer;

public LogEventPropertyValueComparer(IEqualityComparer<object> objectEqualityComparer = null)
{
this._objectEqualityComparer = objectEqualityComparer ?? EqualityComparer<object>.Default;
}

public bool Equals(LogEventPropertyValue x, LogEventPropertyValue y)
{
var scalarX = x as ScalarValue;
var scalarY = y as ScalarValue;
if (scalarX != null && scalarY != null)
{
return _objectEqualityComparer.Equals(scalarX.Value, scalarY.Value);
}

var sequenceX = x as SequenceValue;
var sequenceY = y as SequenceValue;
if (sequenceX != null && sequenceY != null)
{
return sequenceX.Elements
.SequenceEqual(sequenceY.Elements, this);
}

if (x is StructureValue || y is StructureValue)
{
throw new NotImplementedException();
}

if (x is DictionaryValue || y is DictionaryValue)
{
throw new NotImplementedException();
}

return false;
}

public int GetHashCode(LogEventPropertyValue obj)
{
return 0;
}
}
}

0 comments on commit b758729

Please sign in to comment.