} // private void ReportDetailsTests private static void ReportHelpersTests ( ) { const uint DESIRED_WIDTH_MINIMUM = 1; const uint DESIRED_WIDTH_MAXIMUM = 10; const uint ITEM_NUMBER_MINIMUM = 0; const uint ITEM_NUMBER_MAXIMUM = 4; string strTaskName = System.Reflection.MethodBase.GetCurrentMethod ( ).Name; Console.WriteLine ( Properties.Resources.IDS_MSG_BATCH , strTaskName , Properties.Resources.IDS_MSG_BEGIN , Environment.NewLine ); uint uintTestNumber = MagicNumbers.ZERO; uint uintExceptionCount = MagicNumbers.ZERO; long lngTotalTests = MagicNumbers.ZERO; string strHeadingFormat = null; #if DBG_REPORTHELPERSTESTS uint uintItemIndexCounter = MagicNumbers.ZERO; #endif // DBG_REPORTHELPERSTESTS for ( uint uintItemIndex = ITEM_NUMBER_MINIMUM ; uintItemIndex <= ITEM_NUMBER_MAXIMUM ; uintItemIndex++ ) { #if DBG_REPORTHELPERSTESTS Console.WriteLine ( "LOOP DEBUG: uintItemIndexCounter = {0}, uintItemIndex = {1}" , ++uintItemIndexCounter , uintItemIndex ); uint uintMaximumWidthCounter = MagicNumbers.ZERO; #endif // DBG_REPORTHELPERSTESTS for ( uint uintMaximumWidth = DESIRED_WIDTH_MINIMUM ; uintMaximumWidth < DESIRED_WIDTH_MAXIMUM ; uintMaximumWidth++ ) { #if DBG_REPORTHELPERSTESTS Console.WriteLine ( "LOOP DEBUG: uintMaximumWidthCounter = {0}, uintMaximumWidth = {1}" , ++uintMaximumWidthCounter , uintMaximumWidth ); uint uintAlignmentCounter = MagicNumbers.ZERO; #endif // DBG_REPORTHELPERSTESTS foreach ( FormatItem.Alignment enmAlignment in s_aenmAlignment ) { #if DBG_REPORTHELPERSTESTS Console.WriteLine ( "LOOP DEBUG: uintAlignmentCounter = {0}, enmAlignment = {1}" , ++uintAlignmentCounter , enmAlignment ); uint uintTestFormatCounter = MagicNumbers.ZERO; #endif // DBG_REPORTHELPERSTESTS foreach ( string strTestFormat in s_astrFormats ) { #if DBG_REPORTHELPERSTESTS Console.WriteLine ( "LOOP DEBUG: uintTestFormatCounter = {0}, strTestFormat = {1}" , ++uintTestFormatCounter , strTestFormat ); #endif // DBG_REPORTHELPERSTESTS if ( lngTotalTests == MagicNumbers.ZERO ) { lngTotalTests = ( ( ITEM_NUMBER_MAXIMUM - ITEM_NUMBER_MINIMUM ) + ArrayInfo.ORDINAL_FROM_INDEX ) * ( DESIRED_WIDTH_MAXIMUM - DESIRED_WIDTH_MINIMUM ) * s_aenmAlignment.Length * s_astrFormats.Length; strHeadingFormat = FormatItem.UpgradeFormatItem ( Properties.Resources.MSG_NEW_TEST , ITEM_NUMBER_MINIMUM , FormatItem.AdjustToMaximumWidth ( ITEM_NUMBER_MINIMUM , ( uint ) lngTotalTests.ToString ( NumericFormats.NUMBER_PER_REG_SETTINGS_0D ).Length , FormatItem.Alignment.Right , NumericFormats.NUMBER_PER_REG_SETTINGS_0D ) ); } // if ( lngTotalTests == MagicNumbers.ZERO ) Console.WriteLine ( strHeadingFormat , ++uintTestNumber , lngTotalTests , Environment.NewLine ); string strUpgradedFormat = FormatItem.AdjustToMaximumWidth ( uintItemIndex , uintMaximumWidth , enmAlignment , strTestFormat ); ReportDetails rdColl = new ReportDetails ( ); rdColl.Add ( new ReportDetail ( Properties.Resources.MSG_PENMALIGNMENT , ( object ) uintItemIndex ) ); rdColl.Add ( new ReportDetail ( Properties.Resources.MSG_PUINTMAXIMUMWIDTH , ( object ) uintMaximumWidth ) ); rdColl.Add ( new ReportDetail ( Properties.Resources.MSG_PENMALIGNMENT , enmAlignment ) ); rdColl.Add ( new ReportDetail ( Properties.Resources.MSG_PSTRFORMATSTRING , ( object ) strTestFormat ) ); // Coerce strTestFormat into the object. rdColl.Add ( new ReportDetail ( Properties.Resources.MSG_UPGRADED_FORMAT , ( object ) strUpgradedFormat ) ); int uintRequiredWidth = rdColl.WidthOfWidestLabel; foreach ( ReportDetail rdItem in rdColl ) { Console.WriteLine ( ReportDetail.DEFAULT_FORMAT , rdItem.Label.PadRight ( ( int ) uintRequiredWidth ) , rdItem.Value ); } // foreach ( ReportDetail rdItem in rdColl ) // ------------------------------------------------ // There are intentionally programed exceptions in // this test. // ------------------------------------------------ try { Console.WriteLine ( Properties.Resources.MSG_SHOW_SAMPLE_BEFORE_AND_AFTER , Properties.Resources.MSG_SAMPLE_FORMAT_STRING , FormatItem.UpgradeFormatItem ( Properties.Resources.MSG_SAMPLE_FORMAT_STRING , uintItemIndex , strUpgradedFormat ) , Environment.NewLine ); } catch ( Exception exAllKinds ) { rs_appThis.BaseStateManager.AppExceptionLogger.ReportException ( exAllKinds ); uintExceptionCount++; } if ( uintTestNumber == lngTotalTests ) { // We need just one test of this type of error. try { Console.WriteLine ( Properties.Resources.MSG_SHOW_SAMPLE_BEFORE_AND_AFTER , Properties.Resources.MSG_SAMPLE_FORMAT_STRING , FormatItem.UpgradeFormatItem ( Properties.Resources.MSG_SAMPLE_FORMAT_STRING , uintItemIndex , "(4,9:X8)" ) , // This format item is invalid. Environment.NewLine ); } catch ( Exception exAllKinds ) { rs_appThis.BaseStateManager.AppExceptionLogger.ReportException ( exAllKinds ); uintExceptionCount++; } } // if ( uintTestNumber == lngTotalTests ) } // foreach ( string strTestFormat in s_astrFormats ) } // foreach ( FormatItem.Alignment enmAlignment in s_aenmAlignment ) } // for ( uint uintMaximumWidth = MINIMUM_DESIRED_WIDTH ; uintMaximumWidth <= MAXIMUM_DESIRED_WIDTH ; uintMaximumWidth++ ) } // for ( uint uintItemIndex = MINIMUM_ITEM_NUMBER ; uintItemIndex < FORMAT_ITEM_LIMIT ; uintItemIndex++ ) Console.WriteLine ( Properties.Resources.MSG_EXCETIONS_COUNTED , uintExceptionCount , Environment.NewLine ); Console.WriteLine ( Properties.Resources.IDS_MSG_BATCH , strTaskName , Properties.Resources.IDS_MSG_DONE , Environment.NewLine ); } // ReportHelpersTests
} // ListPropertiesPerDefaultToString method (3 of 4) /// <summary> /// Format names and values of the properties reported by the ToString /// method on any object for rendering on a report, such as the console /// display of a character-mode application. /// </summary> /// <param name="pobjToList"> /// Pass in a reference to the object of interest. Its ToString method, /// presumably a custom (overrridden) method is called, and the string /// that it returns is parsed and formatted. /// /// Its ToString method is expected to return a string that begins with /// the object's internal name (type), followed by a colon and a list of /// properties. Each property is expected to be listed as a name-value /// pair, with the name and its value sapearated by an equals sign, and /// properties delimited by either a single character, such as a comma, /// or the platform-dependent newline sequence, e. g., CR/LF for Windows /// or LF for Linux. /// </param> /// <param name="pchrDelimiter"> /// Pass in the single-character delimiter that separates property names /// and their values from each other. To specify that the pairs are /// delimited by newlines, specify SpecialCharacters.NULL_CHAR, the NULL /// (numeric value zero) character. /// </param> /// <param name="pintAdditionalPaddingChars"> /// Specify the number of characters of extra white space, if any, to be /// prepended to subsequent output lines to cause the report to aligne /// vertically. This is useful when the format string through which it /// will be written contains text that precedes the output string, which /// would otherwise cause subsequent detail lines to be misaligned. /// </param> /// <returns> /// The return value is a string that can be fed through a standard /// format item to string.Format, Console.WriteLine, or any of their /// cousins. /// </returns> public static string ListPropertiesPerDefaultToString ( object pobjToList , char pchrDelimiter , int pintAdditionalPaddingChars ) { const string THIRD_FORMAT_ITEM = @" {2}{3}"; StringBuilder rsb = null; string [ ] astrProperties = null; astrProperties = pchrDelimiter == SpecialCharacters.NULL_CHAR ? WizardWrx.EmbeddedTextFile.Readers.StringOfLinesToArray ( pobjToList.ToString ( ) ) : pobjToList.ToString ( ).Split ( pchrDelimiter ); LabelAndValue [ ] autpLabelAndValue = new LabelAndValue [ astrProperties.Length ]; string strTypeName = null; // The string.IsNullOrEmpty method requires an initialized argument. for ( int intIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intIndex < astrProperties.Length ; intIndex++ ) { string [ ] astrLabelAndItsValue = null; if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) { // The first item contains also the property type name, followed by a colon and a space. int intPosColon = astrProperties [ intIndex ].IndexOf ( SpecialCharacters.COLON ); int intPosNext = intPosColon + ArrayInfo.NEXT_INDEX; // ------------------------------------------------ // As always, use a belt and suspenders, covering // the chance that the first label immediately // follows the colon that delimits it from the // object type name. // // Whether the break occurs at the colon or the // immediately following space, the position is set // such that the last charecter goes into the type // name field, leaving the remainder of the string // to be divided into the propertry value and its // label. // ------------------------------------------------ int intPosBreak = ArrayInfo.OrdinalFromIndex ( astrProperties [ intIndex ] [ intPosNext ] == SpecialCharacters.SPACE_CHAR ? intPosNext : intPosColon ); strTypeName = astrProperties [ intIndex ].Substring ( ListInfo.SUBSTR_BEGINNING , intPosBreak ); astrLabelAndItsValue = astrProperties [ intIndex ].Substring ( intPosBreak ).Split ( SpecialCharacters.EQUALS_SIGN ); } // TRUE (This iteration processess the first property item.) block, if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) else { astrLabelAndItsValue = astrProperties [ intIndex ].Split ( SpecialCharacters.EQUALS_SIGN ); } // FALSE (This iteration processes a subsequent property item.) block, if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) autpLabelAndValue [ intIndex ].Label = astrLabelAndItsValue [ ArrayInfo.ARRAY_FIRST_ELEMENT ].Trim ( ); autpLabelAndValue [ intIndex ].Value = astrLabelAndItsValue [ ArrayInfo.ARRAY_SECOND_ELEMENT ].Trim ( ); } // for ( int intIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intIndex < astrProperties.Length ; intIndex++ ) // -------------------------------------------------------- // Compute the length of the longest label string, so that // a format string that renders the labels and their values // in a neatly aligned list can be constructed. // -------------------------------------------------------- int intLabelFieldWidth = ComputeLabelFieldWidth ( autpLabelAndValue ); string strPropertyPadding = SpecialStrings.EMPTY_STRING.PadRight ( strTypeName.Length ); // -------------------------------------------------------- // A string is constructed with two right-padded format // items and a third and fourth default format items. // // 1) The first format item gets the type name string, // strTypeName, on the first iteration of a loop over // the autpLabelAndValue array, while subsequent // iterations use the strPropertyPadding string. // // 2) The second format item gets the property name from // the Label member of a LabelAndValue structure stored // in the current element of the autpLabelAndValue // array. // // 3) The third format item gets the Value member of the // LabelAndValue structure stored in the current // element of the autpLabelAndValue array. // // 4) The fourth format item gets the platform-specific // newline character or sequence thereof. // -------------------------------------------------------- string strDynamicFormatString = string.Concat ( new string [ ] { FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_FIRST_ELEMENT , strTypeName.Length , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , SpecialCharacters.SPACE_CHAR.ToString ( ) , FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_SECOND_ELEMENT , intLabelFieldWidth , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , THIRD_FORMAT_ITEM } ); // -------------------------------------------------------- // The initial capacity of the StringBuilder is twice the // label width plus the length of the type name, times the // number of label/value pairs in the autpLabelAndValue // array. // -------------------------------------------------------- rsb = new StringBuilder ( ( intLabelFieldWidth * MagicNumbers.PLUS_TWO + strTypeName.Length ) * autpLabelAndValue.Length ); for ( int intItemIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intItemIndex < autpLabelAndValue.Length ; intItemIndex++ ) { rsb.AppendFormat ( strDynamicFormatString , new string [ ] { intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ? strTypeName : strPropertyPadding , autpLabelAndValue [ intItemIndex ].Label , autpLabelAndValue [ intItemIndex ].Value , Environment.NewLine } ); // ------------------------------------------------------------ // Unless pintAdditionalPaddingChars is zero, the first pass // generates a new format control string that allows more // characters to its first format item. // ------------------------------------------------------------ if ( pintAdditionalPaddingChars > ListInfo.EMPTY_STRING_LENGTH && intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) { strDynamicFormatString = string.Concat ( new string [ ] { FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_FIRST_ELEMENT , strTypeName.Length + pintAdditionalPaddingChars , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , SpecialCharacters.SPACE_CHAR.ToString ( ) , FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_SECOND_ELEMENT , intLabelFieldWidth , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , THIRD_FORMAT_ITEM } ); } // if ( pintAdditionalPaddingChars > ListInfo.EMPTY_STRING_LENGTH && intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) } // for ( int intItemIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intItemIndex < autpLabelAndValue.Length ; intItemIndex++ ) return rsb.ToString ( ); } // ListPropertiesPerDefaultToString method (4 of 4)