diff --git a/coopy/CompareTable.hx b/coopy/CompareTable.hx index a8ca477..0190a39 100644 --- a/coopy/CompareTable.hx +++ b/coopy/CompareTable.hx @@ -401,6 +401,7 @@ class CompareTable { // we expect headers on row 0 - link them even if quite different. if (ha>0 && hb>0) { align.link(0,0); + align.headers(0,0); } } diff --git a/coopy/DiffSummary.hx b/coopy/DiffSummary.hx new file mode 100644 index 0000000..0ab63be --- /dev/null +++ b/coopy/DiffSummary.hx @@ -0,0 +1,34 @@ +// -*- mode:java; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- + +#if !TOPLEVEL +package coopy; +#end + +/** + * + * Summarize the changes in a diff of a pair of tables + * + */ +@:expose +class DiffSummary { + public var row_deletes : Int; + public var row_inserts : Int; + public var row_updates : Int; + public var row_reorders : Int; + + public var col_deletes : Int; + public var col_inserts : Int; + public var col_updates : Int; + public var col_renames : Int; + public var col_reorders : Int; + + public var row_count_initial_with_header : Int; + public var row_count_final_with_header : Int; + public var row_count_initial : Int; + public var row_count_final : Int; + public var col_count_initial : Int; + public var col_count_final : Int; + + public function new() { + } +} diff --git a/coopy/Mover.hx b/coopy/Mover.hx index 65bb9a3..8d50c05 100644 --- a/coopy/Mover.hx +++ b/coopy/Mover.hx @@ -125,9 +125,9 @@ class Mover { var blks : Array = new Array(); for (k in blk_len.keys()) { blks.push(k); } blks.sort(function(a,b) { - var diff = blk_len.get(b)-blk_len.get(a); - if (diff!=0) return diff; - return a-b; + var diff = blk_len.get(b)-blk_len.get(a); + if (diff==0) diff=a-b; + return diff; }); var moved : Array = new Array(); diff --git a/coopy/TableDiff.hx b/coopy/TableDiff.hx index 9ade791..331d91a 100644 --- a/coopy/TableDiff.hx +++ b/coopy/TableDiff.hx @@ -62,6 +62,18 @@ class TableDiff { private var schema_diff_found : Bool; private var preserve_columns : Bool; + private var row_deletes : Int; + private var row_inserts : Int; + private var row_updates : Int; + private var row_reorders : Int; + + private var col_deletes : Int; + private var col_inserts : Int; + private var col_updates : Int; + private var col_renames : Int; + private var col_reorders : Int; + private var column_units_updated : Map; + private var nested : Bool; private var nesting_present : Bool; @@ -260,6 +272,16 @@ class TableDiff { top_line_done = false; diff_found = false; schema_diff_found = false; + row_deletes = 0; + row_inserts = 0; + row_updates = 0; + row_reorders = 0; + col_deletes = 0; + col_inserts = 0; + col_updates = 0; + col_renames = 0; + col_reorders = 0; + column_units_updated = new Map(); } private function setupTables() : Void { @@ -401,14 +423,24 @@ class TableDiff { have_schema = true; act = "+++"; if (active_column!=null) { - if (allow_update) active_column[j] = 1; + if (allow_update) { + active_column[j] = 1; + } + } + if (allow_update) { + col_inserts++; } } if (cunit.r<0 && cunit.lp()>=0) { have_schema = true; act = "---"; if (active_column!=null) { - if (allow_update) active_column[j] = 1; + if (allow_update) { + active_column[j] = 1; + } + } + if (allow_update) { + col_deletes++; } } if (cunit.r>=0 && cunit.lp()>=0) { @@ -420,7 +452,10 @@ class TableDiff { act = "("; act += v.toString(pp); act += ")"; - if (active_column!=null) active_column[j] = 1; + if (active_column!=null) { + active_column[j] = 1; + col_renames++; + } } } } @@ -428,6 +463,7 @@ class TableDiff { act = ":" + act; have_schema = true; if (active_column!=null) active_column = null; // bail + col_reorders++; } schema.push(act); @@ -756,7 +792,8 @@ class TableDiff { * @param i the index of the row unit * */ - private function scanRow(unit: Unit, output: Table, at: Int, i: Int) { + private function scanRow(unit: Unit, output: Table, at: Int, i: Int, out: Int) { + var row_update : Bool = false; for (j in 0...column_units.length) { var cunit : Unit = column_units[j]; var pp : Dynamic = null; @@ -847,6 +884,10 @@ class TableDiff { var cell : Dynamic = dd; if (have_dd_to&&allow_update) { + if (!row_update) { + if (out==0) row_updates++; + row_update = true; + } if (active_column!=null) { active_column[j] = 1; } @@ -885,6 +926,10 @@ class TableDiff { cell = builder.conflict(dd,dd_to_alt,dd_to); act = conflict_sep; } + if (!column_units_updated.exists(j)) { + column_units_updated.set(j,true); + col_updates++; + } } if (act == "" && have_addition) { act = "+"; @@ -1029,15 +1074,20 @@ class TableDiff { var skip : Bool = false; act = ""; - if (reordered) act = ":"; + if (reordered) { + act = ":"; + if (out==0) row_reorders++; + } if (unit.p<0 && unit.l<0 && unit.r>=0) { if (!allow_insert) skip = true; act = "+++"; + if (out==0 && !skip) row_inserts++; } if ((unit.p>=0||!has_parent) && unit.l>=0 && unit.r<0) { if (!allow_delete) skip = true; act = "---"; + if (out==0 && !skip) row_deletes++; } if (skip) { @@ -1049,7 +1099,7 @@ class TableDiff { continue; } - scanRow(unit,output,at,i); + scanRow(unit,output,at,i,out); } } @@ -1111,5 +1161,31 @@ class TableDiff { if (align==null) return null; return align.comp; } + + /** + * + * Get statistics of the diff - number of rows deleted, updated, + * etc. + * + */ + public function getSummary() : DiffSummary { + var ds = new DiffSummary(); + ds.row_deletes = row_deletes; + ds.row_inserts = row_inserts; + ds.row_updates = row_updates; + ds.row_reorders = row_reorders; + ds.col_deletes = col_deletes; + ds.col_inserts = col_inserts; + ds.col_updates = col_updates; + ds.col_renames = col_renames; + ds.col_reorders = col_reorders; + ds.row_count_initial_with_header = align.getSource().height; + ds.row_count_final_with_header = align.getTarget().height; + ds.row_count_initial = align.getSource().height - align.getSourceHeader() - 1; + ds.row_count_final = align.getTarget().height - align.getTargetHeader() - 1; + ds.col_count_initial = align.getSource().width; + ds.col_count_final = align.getTarget().width; + return ds; + } } diff --git a/harness/BasicTest.hx b/harness/BasicTest.hx index 81f1fe7..7926c7d 100644 --- a/harness/BasicTest.hx +++ b/harness/BasicTest.hx @@ -7,6 +7,8 @@ class BasicTest extends haxe.unit.TestCase { var data2 : Array>; var data3 : Array>; var data4 : Array>; + var data5 : Array>; + var data6 : Array>; override public function setup() { data1 = [['Country','Capital'], @@ -27,6 +29,16 @@ class BasicTest extends haxe.unit.TestCase { ['France','fr','Paris',1], ['Spain','es','Madrid',1], ['Germany','de','Berlin',null]]; + data5 = [['Country','Code','Capital'], + ['Ireland','xie','Dublinx'], + ['France','xfr','Parisx'], + ['Spain','es','Madridx'], + ['Germany','de','Berlinx']]; + data6 = [['Country','Time','Code','Capital','Golfers'], + ['Ireland',0,'ie','Baile Atha Cliath',1000], + ['France',1,'fr','Paris',10000], + ['Spain',1,'es','Madrid',2000], + ['Germany',null,'de','Berlin',2]]; } public function testBasic(){ @@ -39,6 +51,38 @@ class BasicTest extends haxe.unit.TestCase { var highlighter = new coopy.TableDiff(alignment,flags); highlighter.hilite(table_diff); assertEquals(""+table_diff.getCell(0,4),"->"); + assertTrue(highlighter.hasDifference()); + var summary = highlighter.getSummary(); + assertEquals(summary.row_deletes,0); + assertEquals(summary.row_inserts,1); + assertEquals(summary.row_updates,1); + assertEquals(summary.col_deletes,0); + assertEquals(summary.col_inserts,1); + assertEquals(summary.col_updates,1); + assertEquals(summary.row_count_initial_with_header,4); + assertEquals(summary.row_count_final_with_header,5); + assertEquals(summary.row_count_initial,3); + assertEquals(summary.row_count_final,4); + assertEquals(summary.col_count_initial,2); + assertEquals(summary.col_count_final,3); + } + + public function testBasicReversed(){ + var table1 = Native.table(data1); + var table2 = Native.table(data2); + var alignment = coopy.Coopy.compareTables(table2,table1).align(); + var data_diff = []; + var table_diff = Native.table(data_diff); + var flags = new coopy.CompareFlags(); + var highlighter = new coopy.TableDiff(alignment,flags); + highlighter.hilite(table_diff); + var summary = highlighter.getSummary(); + assertEquals(summary.row_deletes,1); + assertEquals(summary.row_inserts,0); + assertEquals(summary.row_updates,1); + assertEquals(summary.col_deletes,1); + assertEquals(summary.col_inserts,0); + assertEquals(summary.col_updates,1); } public function testBasicModern(){ @@ -174,4 +218,47 @@ class BasicTest extends haxe.unit.TestCase { assertEquals(4,table.height); assertEquals(3,table.width); } + + public function testCountColumnChanges() { + var table1 = Native.table(data2); + var table2 = Native.table(data5); + var alignment = coopy.Coopy.compareTables(table1,table2).align(); + var data_diff = []; + var table_diff = Native.table(data_diff); + var flags = new coopy.CompareFlags(); + var highlighter = new coopy.TableDiff(alignment,flags); + highlighter.hilite(table_diff); + var summary = highlighter.getSummary(); + assertEquals(summary.col_updates,2); + } + + public function testCountAddAndMoveColumns() { + var table1 = Native.table(data4); + var table2 = Native.table(data6); + var alignment = coopy.Coopy.compareTables(table1,table2).align(); + var data_diff = []; + var table_diff = Native.table(data_diff); + var flags = new coopy.CompareFlags(); + var highlighter = new coopy.TableDiff(alignment,flags); + highlighter.hilite(table_diff); + var summary = highlighter.getSummary(); + assertEquals(summary.col_inserts,1); + assertEquals(summary.col_reorders,1); + assertEquals(summary.col_deletes,0); + } + + public function testCountAddAndMoveColumnsReversed() { + var table1 = Native.table(data6); + var table2 = Native.table(data4); + var alignment = coopy.Coopy.compareTables(table1,table2).align(); + var data_diff = []; + var table_diff = Native.table(data_diff); + var flags = new coopy.CompareFlags(); + var highlighter = new coopy.TableDiff(alignment,flags); + highlighter.hilite(table_diff); + var summary = highlighter.getSummary(); + assertEquals(summary.col_inserts,0); + assertEquals(summary.col_reorders,1); + assertEquals(summary.col_deletes,1); + } }