/// <summary> /// Diff the given columns of two given files using a given tolerance and method reporting any information back to the StringBuilder passed by ref /// </summary> /// <param name="origfile">the original file</param> /// <param name="newfile">the new file to diff against the original file</param> /// <param name="colnames">the colnames to focus on</param> /// <param name="tolerance">the toleracne to use (absolute value/dp/%age depedning on 'method')</param> /// <param name="method">the method to use when diffing (absolute value/dp/%age)</param> /// <param name="output">a StringBuilder for reporting</param> /// <returns>true if files are approximately the same (within the given tolerance)</returns> internal static bool Diff(InputFile origfile, InputFile newfile, List <string> colnames, decimal tolerance, DiffMethod method, ref StringBuilder output) { Dictionary <string, int> orig_lookup = new Dictionary <string, int>(), new_lookup = new Dictionary <string, int>(); List <string> orig_cols = new List <string>(origfile.ColNames), new_cols = new List <string>(newfile.ColNames); //basic little factory for setting up our comparer object CompareMethod comparer = method == DiffMethod.pct ? (CompareMethod) new PctCompare(tolerance) : method == DiffMethod.abs ? (CompareMethod) new AbsCompare(tolerance) : (CompareMethod) new DPCompare(tolerance); //set up a lookup dictionary to translate between column name and index foreach (string col in colnames) { orig_lookup.Add(col, orig_cols.IndexOf(col)); new_lookup.Add(col, new_cols.IndexOf(col)); } //grab the raw data to diff object[][] origdata = origfile.GetData(true), newdata = newfile.GetData(true); string result = ""; if (origdata.Length != newdata.Length) { result += "The 2 files had different lengths, diff will end at bottom of shortest file" + Environment.NewLine; } object diff; int badhits = 0, ibadline = -1, numlines = (int)Math.Min(origdata.Length, newdata.Length); //for each line in our files for (int i = 0; i < numlines; i++) { //for each column of interest foreach (string col in colnames) { //if we don't have a 'match' (comparer.match takes care of the tolerances for us) if (!comparer.match(origdata[i][orig_lookup[col]], newdata[i][new_lookup[col]], out diff)) { badhits++; //if we haven't picked up any fails on this line yet if (ibadline != i) { //if this isn't the first line of our report then make sure we add a newline if (ibadline >= 0) { output.AppendLine(); } //if it is the first line then make sure we make it clear the file failed else { output.AppendLine("FAIL"); } //print the line number (remember this is the first fail for this line) output.AppendFormat("\t{0,-4}:", i); ibadline = i; } //print out the column name of the value that failed, along with the difference output.AppendFormat("\t{0}:{1}", col, diff); } } } if (badhits == 0) { output.AppendLine("PASS"); } return(badhits == 0); }