def test_nbsp(self): # This table has a numeric difference. # It also has a row full of `<td> </td>` to separate between bulk # of table and the total row. # nbsp won't be decoded nicely by ascii, and it would throw an error: # ``` # UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' # in position 0: ordinal not in range(128) # ``` response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_nbsp_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_nbsp_mod.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(1, response[1]) # count_of_tables self.assertEqual(8, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(72, response[4]) # equals self.assertEqual(0, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_second_file_has_extra_table(self): response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl.htm'), os.path.join(self.diff_files_dir, 'eplustbl_extra_table.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(4, response[1]) # count_of_tables self.assertEqual(0, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(17, response[4]) # equals self.assertEqual(0, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(1, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_invalid_file_2(self): response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl.htm'), os.path.join(self.diff_files_dir, 'eplustbl-DOESNOTEXIST.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertIn('unable to open file', response[0]) # diff status self.assertEqual(0, response[1]) # count_of_tables self.assertEqual(0, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(0, response[4]) # equals self.assertEqual(0, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_malformed_table_heading_in_file_2(self): response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl.htm'), os.path.join(self.diff_files_dir, 'eplustbl_missing_table_header_comment.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertIn('malformed', response[0]) # diff status self.assertEqual(0, response[1]) # count_of_tables self.assertEqual(0, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(0, response[4]) # equals self.assertEqual(0, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_ignore_version_diff(self): # This table has a version number difference response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_versiondiff_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_versiondiff_mod.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(4, response[1]) # count_of_tables self.assertEqual(0, response[2]) # big diffs # TODO This is zero self.assertEqual(0, response[3]) # small diffs self.assertEqual(18, response[4]) # equals self.assertEqual(0, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_unicode_but_not_utf8_encoded_table(self): # degree symbol issue response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_weird_unicode_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_unicode_contents_but_not_utf8_encoded.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(155, response[1]) # count_of_tables self.assertEqual(334, response[2]) # big diffs self.assertEqual(67, response[3]) # small diffs self.assertEqual(3763, response[4]) # equals self.assertEqual(21, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_weird_unicode_issue(self): # There is something about these particular table files that causes an ascii encoding issue # I did not take the time to trim these files down to minimal table outputs, so this also exercises # table diff more heavily than the other tests here response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_weird_unicode_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_weird_unicode_issue_mod.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(155, response[1]) # count_of_tables self.assertEqual(334, response[2]) # big diffs self.assertEqual(67, response[3]) # small diffs self.assertEqual(3763, response[4]) # equals self.assertEqual(21, response[5]) # string diffs self.assertEqual(0, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def test_second_file_has_table_with_different_headings(self): # Basically, if a column heading changed, but no data changed, that column was # ignored, and therefore no diffs, so the column heading change doesn't get noticed. # In fact, if data changed in that ignored column, it got totally ignored. # If a diff is encountered in a different column, the diff calculations ended up hitting # a key error because that column was never added to diff_dict. # We have four files, each with one table, two data columns (FanEnergyIndex and "End Use"), and two rows of data # eplustbl_heading_change_base.htm -- This has a column heading of End Use Subcategory and FEI = 6.21 # eplustbl_heading_change_mod_with_no_other_diffs.htm -- This only has the column name changed to 'End Use' # eplustbl_heading_change_mod_with_diff_in_that_column.htm -- This has 'End Use' and End Use value modified # eplustbl_heading_change_mod_with_diff_in_other_column.htm -- This has 'End Use' and FEI modified to 6.14 # First the only-name-change instance # It should trigger a size change and a string diff # The two FEI values are the same, so there should be two equal values # The heading change should trigger one big diff, and each row (2) should trigger another, so 3 big diffs response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_heading_change_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_heading_change_mod_with_no_other_diffs.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(1, response[1]) # count_of_tables self.assertEqual(3, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(2, response[4]) # equals self.assertEqual(1, response[5]) # string diffs self.assertEqual(1, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2 # For the case where a value in the changed column changes, it should be identical to the just column change # The value will be reported as a big diff because it can't do a comparison due to the heading change # So 3 big diffs still, along with the single size and single string diffs response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_heading_change_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_heading_change_mod_with_diff_in_that_column.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(1, response[1]) # count_of_tables self.assertEqual(3, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(2, response[4]) # equals self.assertEqual(1, response[5]) # string diffs self.assertEqual(1, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2 # Finally the one that was actually causing the issue, where a diff occurred in a different column # We should have the string diff and size diff due to the heading change # We should have a big diff due to the heading change # We should have a big diff for the two values in the changed heading column that can't be compared # And we should have a big diff for the actual change in the other column # So 4 big diffs total, and none equals # Most importantly, it shouldn't crash. response = table_diff( self.thresh_dict, os.path.join(self.diff_files_dir, 'eplustbl_heading_change_base.htm'), os.path.join(self.diff_files_dir, 'eplustbl_heading_change_mod_with_diff_in_other_column.htm'), os.path.join(self.temp_output_dir, 'abs_diff.htm'), os.path.join(self.temp_output_dir, 'rel_diff.htm'), os.path.join(self.temp_output_dir, 'math_diff.log'), os.path.join(self.temp_output_dir, 'summary.htm'), ) self.assertEqual('', response[0]) # diff status self.assertEqual(1, response[1]) # count_of_tables self.assertEqual(4, response[2]) # big diffs self.assertEqual(0, response[3]) # small diffs self.assertEqual(1, response[4]) # equals self.assertEqual(1, response[5]) # string diffs self.assertEqual(1, response[6]) # size errors self.assertEqual(0, response[7]) # in file 2 but not in file 1 self.assertEqual(0, response[8]) # in file 1 but not in file 2
def process_diffs_for_one_case(self, this_entry, ci_mode=False): if ci_mode: # in "ci_mode" the build directory is actually the output directory of each file case_result_dir_1 = self.build_tree_a['build_dir'] case_result_dir_2 = self.build_tree_b['build_dir'] else: case_result_dir_1 = os.path.join(self.build_tree_a['build_dir'], self.test_output_dir, this_entry.basename) case_result_dir_2 = os.path.join(self.build_tree_b['build_dir'], self.test_output_dir, this_entry.basename) out_dir = case_result_dir_1 # we aren't using math_diff and table_diffs summary csv files, so use blanks path_to_math_diff_log = "" path_to_table_diff_log = "" # shortcut join = os.path.join # process the end files first status_case1 = EndErrSummary.STATUS_MISSING status_case2 = EndErrSummary.STATUS_MISSING runtime_case1 = 0 runtime_case2 = 0 end_path = join(case_result_dir_1, 'eplusout.end') if os.path.exists(end_path): [status_case1, runtime_case1] = self.process_end_file(end_path) end_path = join(case_result_dir_2, 'eplusout.end') if os.path.exists(end_path): [status_case2, runtime_case2] = self.process_end_file(end_path) # one quick check here for expect-fatal tests if this_entry.basename == 'EMSTestMathAndKill': if status_case1 == EndErrSummary.STATUS_FATAL and status_case2 == EndErrSummary.STATUS_FATAL: # this is actually what we expect, so add a success result, print a message, and get out this_entry.add_summary_result( EndErrSummary(EndErrSummary.STATUS_SUCCESS, runtime_case1, EndErrSummary.STATUS_SUCCESS, runtime_case2)) self.my_print( "EMSTestMathAndKill Fatal-ed as expected, continuing with no diff checking on it" ) return this_entry # add the initial end/err summary to the entry this_entry.add_summary_result( EndErrSummary(status_case1, runtime_case1, status_case2, runtime_case2)) # Handle the results of the end file before doing anything with diffs # Case 1: Both end files existed, so E+ did complete if not any(x == EndErrSummary.STATUS_MISSING for x in [status_case1, status_case2]): # Case 1a: Both files are successful if sum(x == EndErrSummary.STATUS_SUCCESS for x in [status_case1, status_case2]) == 2: # Just continue to process diffs self.my_print("Processing (Diffs) : %s" % this_entry.basename) # Case 1b: Both completed, but both failed: report that it failed in both cases and return early elif sum(x == EndErrSummary.STATUS_SUCCESS for x in [status_case1, status_case2]) == 0: self.my_print( "Skipping entry because it has a fatal error in both base and mod cases: %s" % this_entry.basename) return this_entry # Case 1c: Both completed, but one failed: report that it failed in one case and return early elif sum(x == EndErrSummary.STATUS_SUCCESS for x in [status_case1, status_case2]) == 1: self.my_print( "Skipping an entry because it appears to have a fatal error in one case: %s" % this_entry.basename) return this_entry # Case 2: Both end files DID NOT exist elif all(x == EndErrSummary.STATUS_MISSING for x in [status_case1, status_case2]): self.my_print( "Skipping entry because it failed (crashed) in both base and mod cases: %s" % this_entry.basename) return this_entry # Case 3: Both end files DID NOT exist elif sum(x == EndErrSummary.STATUS_MISSING for x in [status_case1, status_case2]) == 1: self.my_print( "Skipping an entry because it appears to have failed (crashed) in one case: %s" % this_entry.basename) return this_entry # Case 4: Unhandled combination else: # pragma: no cover -- I don't think we can get here self.my_print( "Skipping an entry because it has an unknown end status: %s" % this_entry.basename) return this_entry # Load diffing threshold dictionary thresh_dict = td.ThreshDict(self.thresh_dict_file) # Do Math (CSV) Diffs if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.csv'): this_entry.add_math_differences( MathDifferences( math_diff.math_diff( thresh_dict, join(case_result_dir_1, 'eplusout.csv'), join(case_result_dir_2, 'eplusout.csv'), join(out_dir, 'eplusout.csv.absdiff.csv'), join(out_dir, 'eplusout.csv.percdiff.csv'), join(out_dir, 'eplusout.csv.diffsummary.csv'), path_to_math_diff_log)), MathDifferences.ESO) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusmtr.csv'): this_entry.add_math_differences( MathDifferences( math_diff.math_diff( thresh_dict, join(case_result_dir_1, 'eplusmtr.csv'), join(case_result_dir_2, 'eplusmtr.csv'), join(out_dir, 'eplusmtr.csv.absdiff.csv'), join(out_dir, 'eplusmtr.csv.percdiff.csv'), join(out_dir, 'eplusmtr.csv.diffsummary.csv'), path_to_math_diff_log)), MathDifferences.MTR) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'epluszsz.csv'): this_entry.add_math_differences( MathDifferences( math_diff.math_diff( thresh_dict, join(case_result_dir_1, 'epluszsz.csv'), join(case_result_dir_2, 'epluszsz.csv'), join(out_dir, 'epluszsz.csv.absdiff.csv'), join(out_dir, 'epluszsz.csv.percdiff.csv'), join(out_dir, 'epluszsz.csv.diffsummary.csv'), path_to_math_diff_log)), MathDifferences.ZSZ) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusssz.csv'): this_entry.add_math_differences( MathDifferences( math_diff.math_diff( thresh_dict, join(case_result_dir_1, 'eplusssz.csv'), join(case_result_dir_2, 'eplusssz.csv'), join(out_dir, 'eplusssz.csv.absdiff.csv'), join(out_dir, 'eplusssz.csv.percdiff.csv'), join(out_dir, 'eplusssz.csv.diffsummary.csv'), path_to_math_diff_log)), MathDifferences.SSZ) # Do Tabular (HTML) Diffs if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplustbl.htm'): this_entry.add_table_differences( TableDifferences( table_diff.table_diff( thresh_dict, join(case_result_dir_1, 'eplustbl.htm'), join(case_result_dir_2, 'eplustbl.htm'), join(out_dir, 'eplustbl.htm.absdiff.htm'), join(out_dir, 'eplustbl.htm.percdiff.htm'), join(out_dir, 'eplustbl.htm.summarydiff.htm'), path_to_table_diff_log))) # Do Textual Diffs if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.audit'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.audit'), join(case_result_dir_2, 'eplusout.audit'), join(out_dir, 'eplusout.audit.diff'))), TextDifferences.AUD) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.bnd'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.bnd'), join(case_result_dir_2, 'eplusout.bnd'), join(out_dir, 'eplusout.bnd.diff'))), TextDifferences.BND) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.dxf'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.dxf'), join(case_result_dir_2, 'eplusout.dxf'), join(out_dir, 'eplusout.dxf.diff'))), TextDifferences.DXF) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.eio'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.eio'), join(case_result_dir_2, 'eplusout.eio'), join(out_dir, 'eplusout.eio.diff'))), TextDifferences.EIO) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.mdd'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.mdd'), join(case_result_dir_2, 'eplusout.mdd'), join(out_dir, 'eplusout.mdd.diff'))), TextDifferences.MDD) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.mtd'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.mtd'), join(case_result_dir_2, 'eplusout.mtd'), join(out_dir, 'eplusout.mtd.diff'))), TextDifferences.MTD) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.rdd'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.rdd'), join(case_result_dir_2, 'eplusout.rdd'), join(out_dir, 'eplusout.rdd.diff'))), TextDifferences.RDD) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.shd'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.shd'), join(case_result_dir_2, 'eplusout.shd'), join(out_dir, 'eplusout.shd.diff'))), TextDifferences.SHD) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.err'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.err'), join(case_result_dir_2, 'eplusout.err'), join(out_dir, 'eplusout.err.diff'))), TextDifferences.ERR) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.delightin'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.delightin'), join(case_result_dir_2, 'eplusout.delightin'), join(out_dir, 'eplusout.delightin.diff'))), TextDifferences.DL_IN) if self.both_files_exist(case_result_dir_1, case_result_dir_2, 'eplusout.delightout'): this_entry.add_text_differences( TextDifferences( self.diff_text_files( join(case_result_dir_1, 'eplusout.delightout'), join(case_result_dir_2, 'eplusout.delightout'), join(out_dir, 'eplusout.delightout.diff'))), TextDifferences.DL_OUT) # return the updated entry return this_entry