#region Apache License // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to you under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; using System.Xml; using log4net.Config; using log4net.Core; using log4net.Layout; using log4net.Repository; using log4net.Tests.Appender; using log4net.Util; using NUnit.Framework; using System.Globalization; namespace log4net.Tests.Layout { [TestFixture] public class XmlLayoutTest { private CultureInfo _currentCulture; private CultureInfo _currentUICulture; [SetUp] public void SetUp() { // set correct thread culture _currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; _currentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture; System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture; } [TearDown] public void TearDown() { // restore previous culture System.Threading.Thread.CurrentThread.CurrentCulture = _currentCulture; System.Threading.Thread.CurrentThread.CurrentUICulture = _currentUICulture; } /// /// Build a basic object with some default values. /// /// A useful LoggingEventData object private LoggingEventData CreateBaseEvent() { LoggingEventData ed = new LoggingEventData(); ed.Domain = "Tests"; ed.ExceptionString = ""; ed.Identity = "TestRunner"; ed.Level = Level.Info; ed.LocationInfo = new LocationInfo(GetType()); ed.LoggerName = "TestLogger"; ed.Message = "Test message"; ed.ThreadName = "TestThread"; ed.TimeStamp = DateTime.Today; ed.UserName = "TestRunner"; ed.Properties = new PropertiesDictionary(); return ed; } private static string CreateEventNode(string message) { return String.Format("{1}" + Environment.NewLine, #if NET_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0 XmlConvert.ToString(DateTime.Today, XmlDateTimeSerializationMode.Local), #else XmlConvert.ToString(DateTime.Today), #endif message); } private static string CreateEventNode(string key, string value) { return String.Format("Test message" + Environment.NewLine, #if NET_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0 XmlConvert.ToString(DateTime.Today, XmlDateTimeSerializationMode.Local), #else XmlConvert.ToString(DateTime.Today), #endif key, value); } [Test] public void TestBasicEventLogging() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("Test message"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestIllegalCharacterMasking() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); evt.Message = "This is a masked char->\uFFFF"; layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("This is a masked char->?"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestCDATAEscaping1() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); //The &'s trigger the use of a cdata block evt.Message = "&&&&&&&Escape this ]]>. End here."; layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("]]. End here.]]>"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestCDATAEscaping2() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); //The &'s trigger the use of a cdata block evt.Message = "&&&&&&&Escape the end ]]>"; layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("]]>"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestCDATAEscaping3() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); //The &'s trigger the use of a cdata block evt.Message = "]]>&&&&&&&Escape the begining"; layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("]]&&&&&&&Escape the begining]]>"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestBase64EventLogging() { TextWriter writer = new StringWriter(); XmlLayout layout = new XmlLayout(); LoggingEventData evt = CreateBaseEvent(); layout.Base64EncodeMessage = true; layout.Format(writer, new LoggingEvent(evt)); string expected = CreateEventNode("VGVzdCBtZXNzYWdl"); Assert.AreEqual(expected, writer.ToString()); } [Test] public void TestPropertyEventLogging() { LoggingEventData evt = CreateBaseEvent(); evt.Properties["Property1"] = "prop1"; XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); log1.Logger.Log(new LoggingEvent(evt)); string expected = CreateEventNode("Property1", "prop1"); Assert.AreEqual(expected, stringAppender.GetString()); } [Test] public void TestBase64PropertyEventLogging() { LoggingEventData evt = CreateBaseEvent(); evt.Properties["Property1"] = "prop1"; XmlLayout layout = new XmlLayout(); layout.Base64EncodeProperties = true; StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); log1.Logger.Log(new LoggingEvent(evt)); string expected = CreateEventNode("Property1", "cHJvcDE="); Assert.AreEqual(expected, stringAppender.GetString()); } [Test] public void TestPropertyCharacterEscaping() { LoggingEventData evt = CreateBaseEvent(); evt.Properties["Property1"] = "prop1 \"quoted\""; XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); log1.Logger.Log(new LoggingEvent(evt)); string expected = CreateEventNode("Property1", "prop1 "quoted""); Assert.AreEqual(expected, stringAppender.GetString()); } [Test] public void TestPropertyIllegalCharacterMasking() { LoggingEventData evt = CreateBaseEvent(); evt.Properties["Property1"] = "mask this ->\uFFFF"; XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); log1.Logger.Log(new LoggingEvent(evt)); string expected = CreateEventNode("Property1", "mask this ->?"); Assert.AreEqual(expected, stringAppender.GetString()); } [Test] public void TestPropertyIllegalCharacterMaskingInName() { LoggingEventData evt = CreateBaseEvent(); evt.Properties["Property\uFFFF"] = "mask this ->\uFFFF"; XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern"); log1.Logger.Log(new LoggingEvent(evt)); string expected = CreateEventNode("Property?", "mask this ->?"); Assert.AreEqual(expected, stringAppender.GetString()); } #if NET_4_0 || MONO_4_0 [Test] public void BracketsInStackTracesKeepLogWellFormed() { XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestLogger"); Action bar = foo => { try { throw new NullReferenceException(); } catch (Exception ex) { log1.Error(string.Format("Error {0}", foo), ex); } }; bar(42); // really only asserts there is no exception var loggedDoc = new XmlDocument(); loggedDoc.LoadXml(stringAppender.GetString()); } [Test] public void BracketsInStackTracesAreEscapedProperly() { XmlLayout layout = new XmlLayout(); StringAppender stringAppender = new StringAppender(); stringAppender.Layout = layout; ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString()); BasicConfigurator.Configure(rep, stringAppender); ILog log1 = LogManager.GetLogger(rep.Name, "TestLogger"); Action bar = foo => { try { throw new NullReferenceException(); } catch (Exception ex) { log1.Error(string.Format("Error {0}", foo), ex); } }; bar(42); var log = stringAppender.GetString(); var startOfExceptionText = log.IndexOf("", StringComparison.InvariantCulture) + 11; var endOfExceptionText = log.IndexOf("", StringComparison.InvariantCulture); var sub = log.Substring(startOfExceptionText, endOfExceptionText - startOfExceptionText); if (sub.StartsWith("", sub); } else { StringAssert.DoesNotContain("<", sub); StringAssert.DoesNotContain(">", sub); } } #endif } }