1 // ***********************************************************************
2 // Copyright (c) 2007 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
30 using System.Collections;
31 using System.Globalization;
32 using NUnit.Framework.Constraints;
34 namespace NUnit.Framework.Internal
37 /// TextMessageWriter writes constraint descriptions and messages
38 /// in displayable form as a text stream. It tailors the display
39 /// of individual message components to form the standard message
40 /// format of NUnit assertion failure messages.
42 public class TextMessageWriter : MessageWriter
44 #region Message Formats and Constants
45 private static readonly int DEFAULT_LINE_LENGTH = 78;
47 // Prefixes used in all failure messages. All must be the same
48 // length, which is held in the PrefixLength field. Should not
49 // contain any tabs or newline characters.
51 /// Prefix used for the expected value line of a message
53 public static readonly string Pfx_Expected = " Expected: ";
55 /// Prefix used for the actual value line of a message
57 public static readonly string Pfx_Actual = " But was: ";
59 /// Length of a message prefix
61 public static readonly int PrefixLength = Pfx_Expected.Length;
65 private int maxLineLength = DEFAULT_LINE_LENGTH;
69 /// Construct a TextMessageWriter
71 public TextMessageWriter() { }
74 /// Construct a TextMessageWriter, specifying a user message
75 /// and optional formatting arguments.
77 /// <param name="userMessage"></param>
78 /// <param name="args"></param>
79 public TextMessageWriter(string userMessage, params object[] args)
81 if ( userMessage != null && userMessage != string.Empty)
82 this.WriteMessageLine(userMessage, args);
88 /// Gets or sets the maximum line length for this writer
90 public override int MaxLineLength
92 get { return maxLineLength; }
93 set { maxLineLength = value; }
97 #region Public Methods - High Level
99 /// Method to write single line message with optional args, usually
100 /// written to precede the general failure message, at a given
101 /// indentation level.
103 /// <param name="level">The indentation level of the message</param>
104 /// <param name="message">The message to be written</param>
105 /// <param name="args">Any arguments used in formatting the message</param>
106 public override void WriteMessageLine(int level, string message, params object[] args)
110 while (level-- >= 0) Write(" ");
112 if (args != null && args.Length > 0)
113 message = string.Format(message, args);
115 WriteLine(MsgUtils.EscapeControlChars(message));
120 /// Display Expected and Actual lines for a constraint. This
121 /// is called by MessageWriter's default implementation of
122 /// WriteMessageTo and provides the generic two-line display.
124 /// <param name="result">The result of the constraint that failed</param>
125 public override void DisplayDifferences(ConstraintResult result)
127 WriteExpectedLine(result);
128 WriteActualLine(result);
132 /// Display Expected and Actual lines for given _values. This
133 /// method may be called by constraints that need more control over
134 /// the display of actual and expected _values than is provided
135 /// by the default implementation.
137 /// <param name="expected">The expected value</param>
138 /// <param name="actual">The actual value causing the failure</param>
139 public override void DisplayDifferences(object expected, object actual)
141 WriteExpectedLine(expected);
142 WriteActualLine(actual);
146 /// Display Expected and Actual lines for given _values, including
147 /// a tolerance value on the expected line.
149 /// <param name="expected">The expected value</param>
150 /// <param name="actual">The actual value causing the failure</param>
151 /// <param name="tolerance">The tolerance within which the test was made</param>
152 public override void DisplayDifferences(object expected, object actual, Tolerance tolerance)
154 WriteExpectedLine(expected, tolerance);
155 WriteActualLine(actual);
159 /// Display the expected and actual string _values on separate lines.
160 /// If the mismatch parameter is >=0, an additional line is displayed
161 /// line containing a caret that points to the mismatch point.
163 /// <param name="expected">The expected string value</param>
164 /// <param name="actual">The actual string value</param>
165 /// <param name="mismatch">The point at which the strings don't match or -1</param>
166 /// <param name="ignoreCase">If true, case is ignored in string comparisons</param>
167 /// <param name="clipping">If true, clip the strings to fit the max line length</param>
168 public override void DisplayStringDifferences(string expected, string actual, int mismatch, bool ignoreCase, bool clipping)
170 // Maximum string we can display without truncating
171 int maxDisplayLength = MaxLineLength
172 - PrefixLength // Allow for prefix
173 - 2; // 2 quotation marks
176 MsgUtils.ClipExpectedAndActual(ref expected, ref actual, maxDisplayLength, mismatch);
178 expected = MsgUtils.EscapeControlChars(expected);
179 actual = MsgUtils.EscapeControlChars(actual);
181 // The mismatch position may have changed due to clipping or white space conversion
182 mismatch = MsgUtils.FindMismatchPosition(expected, actual, 0, ignoreCase);
184 Write( Pfx_Expected );
185 Write( MsgUtils.FormatValue(expected) );
187 Write( ", ignoring case" );
189 WriteActualLine( actual );
190 //DisplayDifferences(expected, actual);
192 WriteCaretLine(mismatch);
196 #region Public Methods - Low Level
199 /// Writes the text for an actual value.
201 /// <param name="actual">The actual value.</param>
202 public override void WriteActualValue(object actual)
208 /// Writes the text for a generalized value.
210 /// <param name="val">The value.</param>
211 public override void WriteValue(object val)
213 Write(MsgUtils.FormatValue(val));
217 /// Writes the text for a collection value,
218 /// starting at a particular point, to a max length
220 /// <param name="collection">The collection containing elements to write.</param>
221 /// <param name="start">The starting point of the elements to write</param>
222 /// <param name="max">The maximum number of elements to write</param>
223 public override void WriteCollectionElements(IEnumerable collection, long start, int max)
225 Write(MsgUtils.FormatCollection(collection, start, max));
230 #region Helper Methods
232 /// Write the generic 'Expected' line for a constraint
234 /// <param name="result">The constraint that failed</param>
235 private void WriteExpectedLine(ConstraintResult result)
238 WriteLine(result.Description);
242 /// Write the generic 'Expected' line for a given value
244 /// <param name="expected">The expected value</param>
245 private void WriteExpectedLine(object expected)
247 WriteExpectedLine(expected, null);
251 /// Write the generic 'Expected' line for a given value
254 /// <param name="expected">The expected value</param>
255 /// <param name="tolerance">The tolerance within which the test was made</param>
256 private void WriteExpectedLine(object expected, Tolerance tolerance)
259 Write(MsgUtils.FormatValue(expected));
261 if (tolerance != null && !tolerance.IsUnsetOrDefault)
264 Write(MsgUtils.FormatValue(tolerance.Value));
265 if (tolerance.Mode != ToleranceMode.Linear)
266 Write(" {0}", tolerance.Mode);
273 /// Write the generic 'Actual' line for a constraint
275 /// <param name="result">The ConstraintResult for which the actual value is to be written</param>
276 private void WriteActualLine(ConstraintResult result)
279 result.WriteActualValueTo(this);
281 //WriteLine(MsgUtils.FormatValue(result.ActualValue));
285 /// Write the generic 'Actual' line for a given value
287 /// <param name="actual">The actual value causing a failure</param>
288 private void WriteActualLine(object actual)
291 WriteActualValue(actual);
295 private void WriteCaretLine(int mismatch)
297 // We subtract 2 for the initial 2 blanks and add back 1 for the initial quote
298 WriteLine(" {0}^", new string('-', PrefixLength + mismatch - 2 + 1));