From 91427d0a01b058da524dac4b5e1c6f14a7ed5275 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Tue, 28 Apr 2020 16:31:13 -0300 Subject: [PATCH 1/8] adding code to diff dbfs changes --- dBASE.NET.Tests/DbfComparerTests.cs | 60 ++++++++++++++ dBASE.NET.Tests/dBASE.NET.Tests.csproj | 18 ++++ .../ModifiedSample/DiffExampleActual.dbf | Bin 0 -> 1452 bytes .../ModifiedSample/DiffExampleNew.dbf | Bin 0 -> 477 bytes .../actual_modified_sample_records.csv | 3 + .../new_modified_sample_records.csv | 3 + .../NewSample/DiffExampleActual.dbf | Bin 0 -> 1452 bytes .../DbfComparer/NewSample/DiffExampleNew.dbf | Bin 0 -> 1966 bytes .../DbfComparer/NewSample/actual_records.csv | 3 + .../DbfComparer/NewSample/new_records.csv | 4 + .../fixtures/DbfComparer/diff_summary.txt | 12 +++ dBASE.NET/DbfDiffExtensions.cs | 78 ++++++++++++++++++ dBASE.NET/DbfRecordDiff.cs | 68 +++++++++++++++ 13 files changed, 249 insertions(+) create mode 100644 dBASE.NET.Tests/DbfComparerTests.cs create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/actual_records.csv create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/new_records.csv create mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/diff_summary.txt create mode 100644 dBASE.NET/DbfDiffExtensions.cs create mode 100644 dBASE.NET/DbfRecordDiff.cs diff --git a/dBASE.NET.Tests/DbfComparerTests.cs b/dBASE.NET.Tests/DbfComparerTests.cs new file mode 100644 index 0000000..752e361 --- /dev/null +++ b/dBASE.NET.Tests/DbfComparerTests.cs @@ -0,0 +1,60 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace dBASE.NET.Tests +{ + [TestClass] + public class DbfComparerTests + { + [TestMethod] + public void Given_Two_Dbf_Files_With_Same_Schema_And_Modified_Records_When_GetDiff_Of_Between_Two_Dbfs_Should_Then_Return_Changed_Records() + { + //Given + string actualFilePath = "fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf"; + string newFilePath = "fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf"; + var actualDbf = new Dbf(); + var newDbf = new Dbf(); + actualDbf.Read(actualFilePath); + newDbf.Read(newFilePath); + //When + var diff = actualDbf.GetDiff(newDbf); + //Then + Assert.AreEqual(2,diff.Count); + } + [TestMethod] + public void Given_Two_Dbf_Files_With_Same_Schema_And_One_New_Record_When_GetDiff_Of_Between_Two_Dbfs_Should_Then_Return_Added_Record() + { + //Given + string actualFilePath = "fixtures/DbfComparer/NewSample/DiffExampleActual.dbf"; + string newFilePath = "fixtures/DbfComparer/NewSample/DiffExampleNew.dbf"; + var actualDbf = new Dbf(); + var newDbf = new Dbf(); + actualDbf.Read(actualFilePath); + newDbf.Read(newFilePath); + //When + var diff = actualDbf.GetDiff(newDbf); + //Then + Assert.AreEqual(4,diff.Count); + } + [TestMethod] + public void Given_DbfRecordDiff_Object_When_Convert_Object_To_String_Should_Then_Return_String_With_Values_Changed() + { + //Given + var diff = new DbfRecordDiff{ + RecordIndex = 1, + State = DiffState.Modified, + ColumnsChanged = new System.Collections.Generic.List{ + new DbfColumnChange{ + Field = new DbfField("Name",DbfFieldType.Character,128), + OldValue = "John", + NewValue = "Joel" + } + } + }; + //, 'RUA SEBASTIAO MOREIRA, 136 ' + string expectedDiffStr = "Index: 1, State: Modified\r\n {\r\n { Name, 'John', 'Joel' }, \r\n }\r\n"; + //When + string diffStr = diff.ToString(); + //Then + Assert.AreEqual(expectedDiffStr,diffStr); + } + } +} \ No newline at end of file diff --git a/dBASE.NET.Tests/dBASE.NET.Tests.csproj b/dBASE.NET.Tests/dBASE.NET.Tests.csproj index 2f8d54b..0f0ade4 100644 --- a/dBASE.NET.Tests/dBASE.NET.Tests.csproj +++ b/dBASE.NET.Tests/dBASE.NET.Tests.csproj @@ -65,6 +65,7 @@ + @@ -109,6 +110,7 @@ PreserveNewest + PreserveNewest @@ -265,6 +267,22 @@ PreserveNewest + + + Always + + + Always + + + + + Always + + + Always + + diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf new file mode 100644 index 0000000000000000000000000000000000000000..b4eefe9446f762b4bf2432a907edce8fa4722dad GIT binary patch literal 1452 zcmXpIVUb~CU|?9m$ONKL0W$-Grwd%jlM%>dVPJy`fEa#`zOGOKXI3EN9|Ni}VU9kb zPzBD+Km*X_Q*$fJxjHTq5J~AU8oZgj;%tvhe15*G1^jVI| literal 0 HcmV?d00001 diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf new file mode 100644 index 0000000000000000000000000000000000000000..e279fade3da59e4024b52d0f72e01f650ce1e14f GIT binary patch literal 477 zcmXpIVUb~CU|?9mCdVPJy`fEa#`zOGOKXI3DCiveUB0)#pG zghCZK^8UQIb8_5r64Q$r3?zZ_j0_-C5P%oK9MLQVP~a>1CFZ6oDFA_zSAIqw Zn8ly~3UDRIbclq4l935mTtR_B3IJm!5%B;3 literal 0 HcmV?d00001 diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv new file mode 100644 index 0000000..5bf0792 --- /dev/null +++ b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv @@ -0,0 +1,3 @@ +id,name,value, +1,"Username","John", +2,"Age","27", diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv new file mode 100644 index 0000000..6c7aebc --- /dev/null +++ b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv @@ -0,0 +1,3 @@ +id,name,value, +1,"Name" ,"John" , +2,"Age" ,"24" , diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf new file mode 100644 index 0000000000000000000000000000000000000000..8bbaff28c86b6e8474b0d4b242ae24c7ea72dc3c GIT binary patch literal 1452 zcmXpIVUb~CU|?9m$ONKL0W$-Grwd%jlM%>dVPJy`fEa#`zOGOKXI3EN9|Ni}VU9kb zPzBD+Km*X_Q*$fJxjHTq5J~AU8oZgj;Oh#<{15*G1@nVk0 literal 0 HcmV?d00001 diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf new file mode 100644 index 0000000000000000000000000000000000000000..b571a3598969cbfd7b621c6383d15713e872930a GIT binary patch literal 1966 zcmXpIVUb~GU|?9m$ixJsPytZF(*-W%$p~b!FtEV|Kny=eUstGrGb@nsj{((~Fh`$I zr~+qZpaJOe@qVQ_Ic_BS5Nj6ki73?NewfEU3W(JTc};4Aqh=B6qsj8LHDm7kF} zVtvn`0LoZOj_D&e0VpULnT*)@S5RP302S0quDOYsIU_X~lw1;vvV-%Bl2eOPi_FZ- V9Mbc1QuLDZbM=ynhJTna004kP)Y + /// Gets the difference between the actual and given dbf file + /// + /// the current open dbf file + /// the dbf file to be compared + /// + public static List GetDiff(this Dbf actualDbf,Dbf targetDbf) + { + var dbfRecordDiff = new List(); + + for (int i = 0; i < actualDbf.Records.Count; i++) + { + var diff = GetRecordDiff(actualDbf,actualDbf.Records[i],targetDbf.Records[i],i); + if(diff.State == DiffState.Modified){ + dbfRecordDiff.Add(diff); + } + } + if(actualDbf.Records.Count < targetDbf.Records.Count){ + dbfRecordDiff.AddRange(targetDbf.Records.Select((r,i) => new DbfRecordDiff{ + RecordIndex = i, + Record = r, + State = DiffState.Added, + ColumnsChanged = r.Data.Select((d,i) => new DbfColumnChange{ + Field = actualDbf.Fields[i], + OldValue = d, + NewValue = d + }).ToList() + })); + } + return dbfRecordDiff; + } + public static DbfRecordDiff GetRecordDiff(Dbf dbf, DbfRecord actualRecord,DbfRecord newRecord,int index) + { + if(actualRecord.Data.SequenceEqual(newRecord.Data)){ + return new DbfRecordDiff(newRecord,index); + } + var recordDiff = new DbfRecordDiff(); + for (int i = 0; i < dbf.Fields.Count; i++){ + var columnActualData = ObjectToByteArray(actualRecord.Data[i]); + var columnNewData = ObjectToByteArray(newRecord.Data[i]); + if(!columnActualData.SequenceEqual(columnNewData)){ + recordDiff.ColumnsChanged.Add(new DbfColumnChange{ + Field = dbf.Fields[i], + OldValue = actualRecord.Data[i], + NewValue = newRecord.Data[i] + }); + } + } + recordDiff.State = DiffState.Modified; + recordDiff.Record = newRecord; + return recordDiff; + + + static byte[] ObjectToByteArray(object obj) + { + if(obj == null) + return null; + var bf = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + bf.Serialize(ms, obj); + return ms.ToArray(); + } + } + } + + + } +} \ No newline at end of file diff --git a/dBASE.NET/DbfRecordDiff.cs b/dBASE.NET/DbfRecordDiff.cs new file mode 100644 index 0000000..af36424 --- /dev/null +++ b/dBASE.NET/DbfRecordDiff.cs @@ -0,0 +1,68 @@ +using System.Text; +using System.Collections.Generic; + +namespace dBASE.NET +{ + public class DbfRecordDiff + { + public DbfRecordDiff() + { + + } + public DbfRecordDiff(DbfRecord record,int recordIndex) + { + Record = record; + RecordIndex = recordIndex; + State = DiffState.Unmodified; + } + public int RecordIndex { get; set; } + public DbfRecord Record { get; set; } + public List ColumnsChanged { get; set; } = new List(); + public DiffState State { get; set; } + public override string ToString() + { + var strBuilder = new StringBuilder(); + strBuilder.AppendFormat("Index: {0}, State: {1}", this.RecordIndex, this.State); + + if ((this.State == DiffState.Modified) || (this.State == DiffState.Added)) + { + strBuilder.AppendLine(); + strBuilder.AppendLine(" {"); + foreach (DbfColumnChange columnDiff in this.ColumnsChanged) + { + strBuilder.Append(" { "); + strBuilder.Append(columnDiff.Field.Name); + + if (this.State == DiffState.Modified) + { + strBuilder.Append(", '"); + strBuilder.Append(columnDiff.OldValue); + strBuilder.Append("'"); + } + + strBuilder.Append(", '"); + strBuilder.Append(columnDiff.NewValue); + strBuilder.Append("'"); + strBuilder.AppendLine(" }, "); + } + + strBuilder.AppendLine(" }"); + } + + return strBuilder.ToString(); + } + } + public class DbfColumnChange + { + public DbfField Field { get; set; } + public object OldValue { get; set; } + public object NewValue { get; set; } + + } + public enum DiffState + { + Modified, + Unmodified, + Added + } +} \ No newline at end of file From 7f3ae90c4fb230a60f8c9beef4f26ee8fdbaa1a1 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Mon, 11 May 2020 16:36:15 -0300 Subject: [PATCH 2/8] adding deleted property and delete methods for records. fix #10 --- dBASE.NET.Tests/Writing.cs | 40 ++++++++++++++++++++++++++++++++-- dBASE.NET/Dbf.cs | 36 ++++++++++++++++++++---------- dBASE.NET/DbfDiffExtensions.cs | 17 +++------------ dBASE.NET/DbfRecord.cs | 13 ++++++----- dBASE.NET/Utils.cs | 36 ++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 32 deletions(-) create mode 100644 dBASE.NET/Utils.cs diff --git a/dBASE.NET.Tests/Writing.cs b/dBASE.NET.Tests/Writing.cs index 0733ca7..f4ec72c 100644 --- a/dBASE.NET.Tests/Writing.cs +++ b/dBASE.NET.Tests/Writing.cs @@ -86,7 +86,33 @@ record = dbf.CreateRecord(); Assert.AreEqual("OUT THERE", dbf.Records[2][0], "Record content should be OUT THERE."); } - + [TestMethod] + public void WriteRecordAndDeleteIt() + { + dbf = new Dbf(); + var field = new DbfField("TEST", DbfFieldType.Character, 12); + dbf.Fields.Add(field); + var record = dbf.CreateRecord(); + record.Data[0] = "HELLO WORLD ! DELETE ME!"; + dbf.DeleteRecord(0); + dbf.Write("test.dbf", DbfVersion.VisualFoxPro); + dbf = new Dbf(); + dbf.Read("test.dbf",false); + Assert.AreEqual(0, dbf.Records.Count,"dbf should have no records"); + } + [TestMethod] + public void WriteMultipleRecordsAndDeleteOne() + { + var dbf = new Dbf(); + var field = new DbfField("TEST", DbfFieldType.Character, 12); + dbf.Fields.Add(field); + AddMultipleRecords(dbf,12); + dbf.DeleteRecord(0); + dbf.Write("test.dbf", DbfVersion.VisualFoxPro); + dbf = new Dbf(); + dbf.Read("test.dbf", false); + Assert.AreEqual(11, dbf.Records.Count,"dbf should have 11 records"); + } [TestMethod] public void NumericField() { @@ -96,7 +122,6 @@ public void NumericField() DbfRecord record = dbf.CreateRecord(); record.Data[0] = 3.14; dbf.Write("test.dbf", DbfVersion.VisualFoxPro); - dbf = new Dbf(); dbf.Read("test.dbf"); @@ -198,5 +223,16 @@ public void CurrencyField() Assert.AreEqual((float) 4.34, dbf.Records[0][0], "Record content should be 4.34."); } + private void AddMultipleRecords(Dbf dbf,int recordsLength) + { + for (int j = 0; j < recordsLength; ++j) + { + var record = dbf.CreateRecord(); + for (int i = 0; i < dbf.Fields.Count; ++i) + { + record.Data[i] = $"test field {i}"; + } + } + } } } diff --git a/dBASE.NET/Dbf.cs b/dBASE.NET/Dbf.cs index fb66fa7..6763109 100644 --- a/dBASE.NET/Dbf.cs +++ b/dBASE.NET/Dbf.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; + using System.Linq; using System.Text; /// @@ -11,8 +12,7 @@ /// public class Dbf { - private DbfHeader header; - + private DbfHeader header; /// /// Initializes a new instance of the . /// @@ -64,21 +64,21 @@ public DbfRecord CreateRecord() /// Opens a DBF file, reads the contents that initialize the current instance, and then closes the file. /// /// The file to read. - public void Read(string path) - { - // Open stream for reading. + public void Read(string path,bool loadDeleted = true) + { + // Open stream for reading. using (FileStream baseStream = File.Open(path, FileMode.Open, FileAccess.Read)) { string memoPath = GetMemoPath(path); if (memoPath == null) { - Read(baseStream); + Read(baseStream,loadDeleted:loadDeleted); } else { using (FileStream memoStream = File.Open(memoPath, FileMode.Open, FileAccess.Read)) { - Read(baseStream, memoStream); + Read(baseStream, memoStream,loadDeleted); } } } @@ -89,7 +89,7 @@ public void Read(string path) /// /// Stream with a database. /// Stream with a memo. - public void Read(Stream baseStream, Stream memoStream = null) + public void Read(Stream baseStream, Stream memoStream = null,bool loadDeleted = true) { if (baseStream == null) { @@ -110,7 +110,7 @@ public void Read(Stream baseStream, Stream memoStream = null) // After reading the fields, we move the read pointer to the beginning // of the records, as indicated by the "HeaderLength" value in the header. baseStream.Seek(header.HeaderLength, SeekOrigin.Begin); - ReadRecords(reader, memoData); + ReadRecords(reader, memoData,loadDeleted); } } @@ -197,15 +197,23 @@ private void ReadFields(BinaryReader reader) reader.ReadByte(); } - private void ReadRecords(BinaryReader reader, byte[] memoData) + private void ReadRecords(BinaryReader reader, byte[] memoData,bool loadDeleted) { Records.Clear(); // Records are terminated by 0x1a char (officially), or EOF (also seen). while (reader.PeekChar() != 0x1a && reader.PeekChar() != -1) { + var isDeletedMarker = (byte)reader.PeekChar() == (byte)0x2A; + if (isDeletedMarker) + { + reader.ReadBytes(header.RecordLength); + continue; + } try { + + Records.Add(new DbfRecord(reader, header, Fields, memoData, Encoding)); } catch (EndOfStreamException) { } @@ -233,7 +241,13 @@ private void WriteRecords(BinaryWriter writer) // Write EOF character. writer.Write((byte)0x1a); } - + /// + /// Write the delete Mark as deleted + /// + public void DeleteRecord(int index) + { + this.Records[index].DeleteRecord(); + } private static string GetMemoPath(string basePath) { string memoPath = Path.ChangeExtension(basePath, "fpt"); diff --git a/dBASE.NET/DbfDiffExtensions.cs b/dBASE.NET/DbfDiffExtensions.cs index 72105f0..ad35646 100644 --- a/dBASE.NET/DbfDiffExtensions.cs +++ b/dBASE.NET/DbfDiffExtensions.cs @@ -45,8 +45,8 @@ public static DbfRecordDiff GetRecordDiff(Dbf dbf, DbfRecord actualRecord,DbfRec } var recordDiff = new DbfRecordDiff(); for (int i = 0; i < dbf.Fields.Count; i++){ - var columnActualData = ObjectToByteArray(actualRecord.Data[i]); - var columnNewData = ObjectToByteArray(newRecord.Data[i]); + var columnActualData = Utils.ObjectToByteArray(actualRecord.Data[i]); + var columnNewData = Utils.ObjectToByteArray(newRecord.Data[i]); if(!columnActualData.SequenceEqual(columnNewData)){ recordDiff.ColumnsChanged.Add(new DbfColumnChange{ Field = dbf.Fields[i], @@ -59,18 +59,7 @@ public static DbfRecordDiff GetRecordDiff(Dbf dbf, DbfRecord actualRecord,DbfRec recordDiff.Record = newRecord; return recordDiff; - - static byte[] ObjectToByteArray(object obj) - { - if(obj == null) - return null; - var bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, obj); - return ms.ToArray(); - } - } + } diff --git a/dBASE.NET/DbfRecord.cs b/dBASE.NET/DbfRecord.cs index 551a0ab..a433a53 100644 --- a/dBASE.NET/DbfRecord.cs +++ b/dBASE.NET/DbfRecord.cs @@ -25,7 +25,7 @@ internal DbfRecord(BinaryReader reader, DbfHeader header, List fields, // Read record marker. byte marker = reader.ReadByte(); - + Deleted = marker == 0x2A; // Read entire record as sequence of bytes. // Note that record length includes marker. byte[] row = reader.ReadBytes(header.RecordLength - 1); @@ -55,7 +55,7 @@ internal DbfRecord(List fields) Data = new List(); foreach (DbfField field in fields) Data.Add(null); } - + public bool Deleted { get; private set; } public List Data { get; } public object this[int index] => Data[index]; @@ -79,7 +79,7 @@ public object this[DbfField field] return Data[index]; } } - + /// /// Returns a string that represents the current object. /// @@ -115,11 +115,14 @@ public string ToString(string separator, string mask) return string.Join(separator, fields.Select(z => string.Format(mask, z.Name, this[z]))); } - + internal void DeleteRecord() + { + Deleted = true; + } internal void Write(BinaryWriter writer, Encoding encoding) { // Write marker (always "not deleted") - writer.Write((byte)0x20); + writer.Write(Deleted ? (byte)0x2A : (byte)0x20); int index = 0; foreach (DbfField field in fields) diff --git a/dBASE.NET/Utils.cs b/dBASE.NET/Utils.cs new file mode 100644 index 0000000..0e2338d --- /dev/null +++ b/dBASE.NET/Utils.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; + +namespace dBASE.NET +{ + public static class Utils + { + public static byte[] ObjectToByteArray(object obj) + { + if (obj == null) + return null; + var bf = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + bf.Serialize(ms, obj); + return ms.ToArray(); + } + } + public static Stream ObjectToMemoryStream(object obj) + { + if (obj == null) + return null; + var bf = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + bf.Serialize(ms, obj); + return ms; + } + } + } +} From cf9f0912ed23201df66a51350d3da4f122ef1621 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Mon, 11 May 2020 16:37:01 -0300 Subject: [PATCH 3/8] removing Utils.ObjectToStream Method --- dBASE.NET/Utils.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dBASE.NET/Utils.cs b/dBASE.NET/Utils.cs index 0e2338d..bae2cc3 100644 --- a/dBASE.NET/Utils.cs +++ b/dBASE.NET/Utils.cs @@ -20,17 +20,6 @@ public static byte[] ObjectToByteArray(object obj) bf.Serialize(ms, obj); return ms.ToArray(); } - } - public static Stream ObjectToMemoryStream(object obj) - { - if (obj == null) - return null; - var bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, obj); - return ms; - } - } + } } } From 352466fcc61a18683f7edb5508fe551b15b4f60f Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Wed, 24 Jun 2020 12:26:30 -0300 Subject: [PATCH 4/8] removing some non related parts --- dBASE.NET.Tests/DbfComparerTests.cs | 60 ----------------------- dBASE.NET.Tests/dBASE.NET.Tests.csproj | 1 - dBASE.NET/DbfDiffExtensions.cs | 67 ------------------------- dBASE.NET/DbfRecordDiff.cs | 68 -------------------------- 4 files changed, 196 deletions(-) delete mode 100644 dBASE.NET.Tests/DbfComparerTests.cs delete mode 100644 dBASE.NET/DbfDiffExtensions.cs delete mode 100644 dBASE.NET/DbfRecordDiff.cs diff --git a/dBASE.NET.Tests/DbfComparerTests.cs b/dBASE.NET.Tests/DbfComparerTests.cs deleted file mode 100644 index 752e361..0000000 --- a/dBASE.NET.Tests/DbfComparerTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace dBASE.NET.Tests -{ - [TestClass] - public class DbfComparerTests - { - [TestMethod] - public void Given_Two_Dbf_Files_With_Same_Schema_And_Modified_Records_When_GetDiff_Of_Between_Two_Dbfs_Should_Then_Return_Changed_Records() - { - //Given - string actualFilePath = "fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf"; - string newFilePath = "fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf"; - var actualDbf = new Dbf(); - var newDbf = new Dbf(); - actualDbf.Read(actualFilePath); - newDbf.Read(newFilePath); - //When - var diff = actualDbf.GetDiff(newDbf); - //Then - Assert.AreEqual(2,diff.Count); - } - [TestMethod] - public void Given_Two_Dbf_Files_With_Same_Schema_And_One_New_Record_When_GetDiff_Of_Between_Two_Dbfs_Should_Then_Return_Added_Record() - { - //Given - string actualFilePath = "fixtures/DbfComparer/NewSample/DiffExampleActual.dbf"; - string newFilePath = "fixtures/DbfComparer/NewSample/DiffExampleNew.dbf"; - var actualDbf = new Dbf(); - var newDbf = new Dbf(); - actualDbf.Read(actualFilePath); - newDbf.Read(newFilePath); - //When - var diff = actualDbf.GetDiff(newDbf); - //Then - Assert.AreEqual(4,diff.Count); - } - [TestMethod] - public void Given_DbfRecordDiff_Object_When_Convert_Object_To_String_Should_Then_Return_String_With_Values_Changed() - { - //Given - var diff = new DbfRecordDiff{ - RecordIndex = 1, - State = DiffState.Modified, - ColumnsChanged = new System.Collections.Generic.List{ - new DbfColumnChange{ - Field = new DbfField("Name",DbfFieldType.Character,128), - OldValue = "John", - NewValue = "Joel" - } - } - }; - //, 'RUA SEBASTIAO MOREIRA, 136 ' - string expectedDiffStr = "Index: 1, State: Modified\r\n {\r\n { Name, 'John', 'Joel' }, \r\n }\r\n"; - //When - string diffStr = diff.ToString(); - //Then - Assert.AreEqual(expectedDiffStr,diffStr); - } - } -} \ No newline at end of file diff --git a/dBASE.NET.Tests/dBASE.NET.Tests.csproj b/dBASE.NET.Tests/dBASE.NET.Tests.csproj index 0f0ade4..bab25b7 100644 --- a/dBASE.NET.Tests/dBASE.NET.Tests.csproj +++ b/dBASE.NET.Tests/dBASE.NET.Tests.csproj @@ -65,7 +65,6 @@ - diff --git a/dBASE.NET/DbfDiffExtensions.cs b/dBASE.NET/DbfDiffExtensions.cs deleted file mode 100644 index ad35646..0000000 --- a/dBASE.NET/DbfDiffExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization.Formatters.Binary; - -namespace dBASE.NET -{ - public static class DbfDiffExtensions - { - /// - /// Gets the difference between the actual and given dbf file - /// - /// the current open dbf file - /// the dbf file to be compared - /// - public static List GetDiff(this Dbf actualDbf,Dbf targetDbf) - { - var dbfRecordDiff = new List(); - - for (int i = 0; i < actualDbf.Records.Count; i++) - { - var diff = GetRecordDiff(actualDbf,actualDbf.Records[i],targetDbf.Records[i],i); - if(diff.State == DiffState.Modified){ - dbfRecordDiff.Add(diff); - } - } - if(actualDbf.Records.Count < targetDbf.Records.Count){ - dbfRecordDiff.AddRange(targetDbf.Records.Select((r,i) => new DbfRecordDiff{ - RecordIndex = i, - Record = r, - State = DiffState.Added, - ColumnsChanged = r.Data.Select((d,i) => new DbfColumnChange{ - Field = actualDbf.Fields[i], - OldValue = d, - NewValue = d - }).ToList() - })); - } - return dbfRecordDiff; - } - public static DbfRecordDiff GetRecordDiff(Dbf dbf, DbfRecord actualRecord,DbfRecord newRecord,int index) - { - if(actualRecord.Data.SequenceEqual(newRecord.Data)){ - return new DbfRecordDiff(newRecord,index); - } - var recordDiff = new DbfRecordDiff(); - for (int i = 0; i < dbf.Fields.Count; i++){ - var columnActualData = Utils.ObjectToByteArray(actualRecord.Data[i]); - var columnNewData = Utils.ObjectToByteArray(newRecord.Data[i]); - if(!columnActualData.SequenceEqual(columnNewData)){ - recordDiff.ColumnsChanged.Add(new DbfColumnChange{ - Field = dbf.Fields[i], - OldValue = actualRecord.Data[i], - NewValue = newRecord.Data[i] - }); - } - } - recordDiff.State = DiffState.Modified; - recordDiff.Record = newRecord; - return recordDiff; - - - } - - - } -} \ No newline at end of file diff --git a/dBASE.NET/DbfRecordDiff.cs b/dBASE.NET/DbfRecordDiff.cs deleted file mode 100644 index af36424..0000000 --- a/dBASE.NET/DbfRecordDiff.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Text; -using System.Collections.Generic; - -namespace dBASE.NET -{ - public class DbfRecordDiff - { - public DbfRecordDiff() - { - - } - public DbfRecordDiff(DbfRecord record,int recordIndex) - { - Record = record; - RecordIndex = recordIndex; - State = DiffState.Unmodified; - } - public int RecordIndex { get; set; } - public DbfRecord Record { get; set; } - public List ColumnsChanged { get; set; } = new List(); - public DiffState State { get; set; } - public override string ToString() - { - var strBuilder = new StringBuilder(); - strBuilder.AppendFormat("Index: {0}, State: {1}", this.RecordIndex, this.State); - - if ((this.State == DiffState.Modified) || (this.State == DiffState.Added)) - { - strBuilder.AppendLine(); - strBuilder.AppendLine(" {"); - foreach (DbfColumnChange columnDiff in this.ColumnsChanged) - { - strBuilder.Append(" { "); - strBuilder.Append(columnDiff.Field.Name); - - if (this.State == DiffState.Modified) - { - strBuilder.Append(", '"); - strBuilder.Append(columnDiff.OldValue); - strBuilder.Append("'"); - } - - strBuilder.Append(", '"); - strBuilder.Append(columnDiff.NewValue); - strBuilder.Append("'"); - strBuilder.AppendLine(" }, "); - } - - strBuilder.AppendLine(" }"); - } - - return strBuilder.ToString(); - } - } - public class DbfColumnChange - { - public DbfField Field { get; set; } - public object OldValue { get; set; } - public object NewValue { get; set; } - - } - public enum DiffState - { - Modified, - Unmodified, - Added - } -} \ No newline at end of file From 4b9be48a168cc889198c1c5a448bdf6a4b288429 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Wed, 24 Jun 2020 12:30:57 -0300 Subject: [PATCH 5/8] removing data from dbf diff functions --- .../ModifiedSample/DiffExampleActual.dbf | Bin 1452 -> 0 bytes .../ModifiedSample/DiffExampleNew.dbf | Bin 477 -> 0 bytes .../actual_modified_sample_records.csv | 3 --- .../new_modified_sample_records.csv | 3 --- .../DbfComparer/NewSample/DiffExampleActual.dbf | Bin 1452 -> 0 bytes .../DbfComparer/NewSample/DiffExampleNew.dbf | Bin 1966 -> 0 bytes .../DbfComparer/NewSample/actual_records.csv | 3 --- .../DbfComparer/NewSample/new_records.csv | 4 ---- .../fixtures/DbfComparer/diff_summary.txt | 12 ------------ 9 files changed, 25 deletions(-) delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/actual_records.csv delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/NewSample/new_records.csv delete mode 100644 dBASE.NET.Tests/fixtures/DbfComparer/diff_summary.txt diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleActual.dbf deleted file mode 100644 index b4eefe9446f762b4bf2432a907edce8fa4722dad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1452 zcmXpIVUb~CU|?9m$ONKL0W$-Grwd%jlM%>dVPJy`fEa#`zOGOKXI3EN9|Ni}VU9kb zPzBD+Km*X_Q*$fJxjHTq5J~AU8oZgj;%tvhe15*G1^jVI| diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/DiffExampleNew.dbf deleted file mode 100644 index e279fade3da59e4024b52d0f72e01f650ce1e14f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 477 zcmXpIVUb~CU|?9mCdVPJy`fEa#`zOGOKXI3DCiveUB0)#pG zghCZK^8UQIb8_5r64Q$r3?zZ_j0_-C5P%oK9MLQVP~a>1CFZ6oDFA_zSAIqw Zn8ly~3UDRIbclq4l935mTtR_B3IJm!5%B;3 diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv deleted file mode 100644 index 5bf0792..0000000 --- a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/actual_modified_sample_records.csv +++ /dev/null @@ -1,3 +0,0 @@ -id,name,value, -1,"Username","John", -2,"Age","27", diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv b/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv deleted file mode 100644 index 6c7aebc..0000000 --- a/dBASE.NET.Tests/fixtures/DbfComparer/ModifiedSample/new_modified_sample_records.csv +++ /dev/null @@ -1,3 +0,0 @@ -id,name,value, -1,"Name" ,"John" , -2,"Age" ,"24" , diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleActual.dbf deleted file mode 100644 index 8bbaff28c86b6e8474b0d4b242ae24c7ea72dc3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1452 zcmXpIVUb~CU|?9m$ONKL0W$-Grwd%jlM%>dVPJy`fEa#`zOGOKXI3EN9|Ni}VU9kb zPzBD+Km*X_Q*$fJxjHTq5J~AU8oZgj;Oh#<{15*G1@nVk0 diff --git a/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf b/dBASE.NET.Tests/fixtures/DbfComparer/NewSample/DiffExampleNew.dbf deleted file mode 100644 index b571a3598969cbfd7b621c6383d15713e872930a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1966 zcmXpIVUb~GU|?9m$ixJsPytZF(*-W%$p~b!FtEV|Kny=eUstGrGb@nsj{((~Fh`$I zr~+qZpaJOe@qVQ_Ic_BS5Nj6ki73?NewfEU3W(JTc};4Aqh=B6qsj8LHDm7kF} zVtvn`0LoZOj_D&e0VpULnT*)@S5RP302S0quDOYsIU_X~lw1;vvV-%Bl2eOPi_FZ- V9Mbc1QuLDZbM=ynhJTna004kP)Y Date: Wed, 24 Jun 2020 12:34:00 -0300 Subject: [PATCH 6/8] removing Utils class --- dBASE.NET/Utils.cs | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 dBASE.NET/Utils.cs diff --git a/dBASE.NET/Utils.cs b/dBASE.NET/Utils.cs deleted file mode 100644 index bae2cc3..0000000 --- a/dBASE.NET/Utils.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using System.Threading.Tasks; - -namespace dBASE.NET -{ - public static class Utils - { - public static byte[] ObjectToByteArray(object obj) - { - if (obj == null) - return null; - var bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, obj); - return ms.ToArray(); - } - } - } -} From 9cd9f88daffe32500304dabc69f5f47a1df97f47 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Wed, 24 Jun 2020 12:36:58 -0300 Subject: [PATCH 7/8] and removing unused parts of the .Tests csproj --- dBASE.NET.Tests/dBASE.NET.Tests.csproj | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/dBASE.NET.Tests/dBASE.NET.Tests.csproj b/dBASE.NET.Tests/dBASE.NET.Tests.csproj index bab25b7..2f8d54b 100644 --- a/dBASE.NET.Tests/dBASE.NET.Tests.csproj +++ b/dBASE.NET.Tests/dBASE.NET.Tests.csproj @@ -109,7 +109,6 @@ PreserveNewest - PreserveNewest @@ -266,22 +265,6 @@ PreserveNewest - - - Always - - - Always - - - - - Always - - - Always - - From afaaf89a7be45521e0b731c4d3d04cacbb905a41 Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Wed, 24 Jun 2020 13:09:07 -0300 Subject: [PATCH 8/8] adding more unit tests and one function to delete multiple records --- dBASE.NET.Tests/Writing.cs | 32 ++++++++++++++++++++++++++++++-- dBASE.NET/Dbf.cs | 12 ++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/dBASE.NET.Tests/Writing.cs b/dBASE.NET.Tests/Writing.cs index f4ec72c..f54156b 100644 --- a/dBASE.NET.Tests/Writing.cs +++ b/dBASE.NET.Tests/Writing.cs @@ -2,7 +2,7 @@ { using System; using System.IO; - + using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -114,6 +114,34 @@ public void WriteMultipleRecordsAndDeleteOne() Assert.AreEqual(11, dbf.Records.Count,"dbf should have 11 records"); } [TestMethod] + public void WriteMultipleRecordsAndDeleteAll() + { + var dbf = new Dbf(); + var field = new DbfField("TEST", DbfFieldType.Character, 12); + dbf.Fields.Add(field); + AddMultipleRecords(dbf, 12); + dbf.DeleteRecords(Enumerable.Range(0,12).ToArray()); + dbf.Write("test.dbf", DbfVersion.VisualFoxPro); + dbf = new Dbf(); + dbf.Read("test.dbf", false); + Assert.AreEqual(0, dbf.Records.Count, "dbf should have no record"); + } + + [TestMethod] + public void WriteRecordAndDeleteButLoadDeletedRecords() + { + dbf = new Dbf(); + var field = new DbfField("TEST", DbfFieldType.Character, 12); + dbf.Fields.Add(field); + var record = dbf.CreateRecord(); + record.Data[0] = "HELLO WORLD ! DELETE ME!"; + dbf.DeleteRecord(0); + dbf.Write("test.dbf", DbfVersion.VisualFoxPro); + dbf = new Dbf(); + dbf.Read("test.dbf"); + Assert.AreEqual(0, dbf.Records.Count, "dbf should have no records"); + } + [TestMethod] public void NumericField() { dbf = new Dbf(); @@ -233,6 +261,6 @@ private void AddMultipleRecords(Dbf dbf,int recordsLength) record.Data[i] = $"test field {i}"; } } - } + } } } diff --git a/dBASE.NET/Dbf.cs b/dBASE.NET/Dbf.cs index 6763109..ff610be 100644 --- a/dBASE.NET/Dbf.cs +++ b/dBASE.NET/Dbf.cs @@ -244,10 +244,22 @@ private void WriteRecords(BinaryWriter writer) /// /// Write the delete Mark as deleted /// + /// /// the index of the file to be deleted public void DeleteRecord(int index) { this.Records[index].DeleteRecord(); } + /// + /// Delete multiple records from theirs indexes on record list + /// + /// + public void DeleteRecords(params int[] indexes) + { + for (int i = 0; i < indexes.Length; i++) + { + DeleteRecord(indexes[i]); + } + } private static string GetMemoPath(string basePath) { string memoPath = Path.ChangeExtension(basePath, "fpt");