|
| 1 | +using System.IO; |
| 2 | +using System.Linq; |
| 3 | +using DocumentFormat.OpenXml.Packaging; |
| 4 | +using DocumentFormat.OpenXml.Wordprocessing; |
| 5 | +using OfficeIMO.Word; |
| 6 | +using Xunit; |
| 7 | +using V = DocumentFormat.OpenXml.Vml; |
| 8 | + |
| 9 | +namespace OfficeIMO.Tests { |
| 10 | + public partial class Word { |
| 11 | + [Fact] |
| 12 | + public void CompareStructureTreatsMovedBodyParagraphToHeaderAsDeleteInsert() { |
| 13 | + string sourcePath = Path.Combine(_directoryWithFiles, "compare_structure_source_body_to_header.docx"); |
| 14 | + using (WordDocument doc = WordDocument.Create(sourcePath)) { |
| 15 | + doc.AddParagraph("Body anchor"); |
| 16 | + doc.AddParagraph("Classification: Confidential"); |
| 17 | + doc.Save(false); |
| 18 | + } |
| 19 | + |
| 20 | + string targetPath = Path.Combine(_directoryWithFiles, "compare_structure_target_body_to_header.docx"); |
| 21 | + using (WordDocument doc = WordDocument.Create(targetPath)) { |
| 22 | + doc.AddParagraph("Body anchor"); |
| 23 | + doc.AddHeadersAndFooters(); |
| 24 | + doc.Header.Default!.AddParagraph("Classification: Confidential"); |
| 25 | + doc.Save(false); |
| 26 | + } |
| 27 | + |
| 28 | + WordComparisonResult result = WordDocumentComparer.CompareStructure(sourcePath, targetPath); |
| 29 | + |
| 30 | + Assert.Contains(result.Findings, finding => |
| 31 | + finding.Scope == WordComparisonScope.Paragraph && |
| 32 | + finding.ChangeKind == WordComparisonChangeKind.Deleted && |
| 33 | + finding.SourceText == "Classification: Confidential"); |
| 34 | + Assert.Contains(result.Findings, finding => |
| 35 | + finding.Scope == WordComparisonScope.Paragraph && |
| 36 | + finding.ChangeKind == WordComparisonChangeKind.Inserted && |
| 37 | + finding.TargetText == "Classification: Confidential"); |
| 38 | + Assert.DoesNotContain(result.Findings, finding => |
| 39 | + finding.Scope == WordComparisonScope.Paragraph && |
| 40 | + finding.ChangeKind == WordComparisonChangeKind.Modified && |
| 41 | + finding.SourceText == "Classification: Confidential" && |
| 42 | + finding.TargetText == "Classification: Confidential"); |
| 43 | + } |
| 44 | + |
| 45 | + [Fact] |
| 46 | + public void CompareStructurePreservesPageAndColumnBreaksInParagraphText() { |
| 47 | + string sourcePath = Path.Combine(_directoryWithFiles, "compare_structure_source_page_break.docx"); |
| 48 | + using (WordDocument doc = WordDocument.Create(sourcePath)) { |
| 49 | + AddBreakParagraph(doc, BreakValues.Page); |
| 50 | + doc.Save(false); |
| 51 | + } |
| 52 | + |
| 53 | + string targetPath = Path.Combine(_directoryWithFiles, "compare_structure_target_column_break.docx"); |
| 54 | + using (WordDocument doc = WordDocument.Create(targetPath)) { |
| 55 | + AddBreakParagraph(doc, BreakValues.Column); |
| 56 | + doc.Save(false); |
| 57 | + } |
| 58 | + |
| 59 | + WordComparisonResult result = WordDocumentComparer.CompareStructure(sourcePath, targetPath); |
| 60 | + |
| 61 | + WordComparisonFinding modified = Assert.Single(result.Findings, finding => |
| 62 | + finding.Scope == WordComparisonScope.Paragraph && |
| 63 | + finding.ChangeKind == WordComparisonChangeKind.Modified); |
| 64 | + Assert.Equal("Before[PageBreak]After", modified.SourceText); |
| 65 | + Assert.Equal("Before[ColumnBreak]After", modified.TargetText); |
| 66 | + } |
| 67 | + |
| 68 | + [Fact] |
| 69 | + public void CompareStructureReportsVmlImageReplacement() { |
| 70 | + string sourcePath = Path.Combine(_directoryWithFiles, "compare_structure_source_vml_image.docx"); |
| 71 | + using (WordDocument doc = WordDocument.Create(sourcePath)) { |
| 72 | + AddVmlImageParagraph(doc, Path.Combine(_directoryWithImages, "EvotecLogo.png")); |
| 73 | + doc.Save(false); |
| 74 | + } |
| 75 | + |
| 76 | + string targetPath = Path.Combine(_directoryWithFiles, "compare_structure_target_vml_image.docx"); |
| 77 | + using (WordDocument doc = WordDocument.Create(targetPath)) { |
| 78 | + AddVmlImageParagraph(doc, Path.Combine(_directoryWithImages, "Kulek.jpg")); |
| 79 | + doc.Save(false); |
| 80 | + } |
| 81 | + |
| 82 | + WordComparisonResult result = WordDocumentComparer.CompareStructure(sourcePath, targetPath); |
| 83 | + |
| 84 | + WordComparisonFinding image = Assert.Single(result.Findings, finding => |
| 85 | + finding.Scope == WordComparisonScope.Image && |
| 86 | + finding.ChangeKind == WordComparisonChangeKind.Modified); |
| 87 | + Assert.Equal("image[0]", image.Location); |
| 88 | + } |
| 89 | + |
| 90 | + [Fact] |
| 91 | + public void CompareStructureReadsBlockContentControlTextInsideTableCells() { |
| 92 | + string sourcePath = Path.Combine(_directoryWithFiles, "compare_structure_source_cell_sdt.docx"); |
| 93 | + using (WordDocument doc = WordDocument.Create(sourcePath)) { |
| 94 | + WordTable table = doc.AddTable(1, 1); |
| 95 | + ReplaceCellWithBlockContentControl(table.Rows[0].Cells[0], "Evidence pending"); |
| 96 | + doc.Save(false); |
| 97 | + } |
| 98 | + |
| 99 | + string targetPath = Path.Combine(_directoryWithFiles, "compare_structure_target_cell_sdt.docx"); |
| 100 | + using (WordDocument doc = WordDocument.Create(targetPath)) { |
| 101 | + WordTable table = doc.AddTable(1, 1); |
| 102 | + ReplaceCellWithBlockContentControl(table.Rows[0].Cells[0], "Evidence approved"); |
| 103 | + doc.Save(false); |
| 104 | + } |
| 105 | + |
| 106 | + WordComparisonResult result = WordDocumentComparer.CompareStructure(sourcePath, targetPath); |
| 107 | + |
| 108 | + WordComparisonFinding cell = Assert.Single(result.Findings, finding => |
| 109 | + finding.Scope == WordComparisonScope.TableCell && |
| 110 | + finding.ChangeKind == WordComparisonChangeKind.Modified); |
| 111 | + Assert.Equal("Evidence pending", cell.SourceText); |
| 112 | + Assert.Equal("Evidence approved", cell.TargetText); |
| 113 | + } |
| 114 | + |
| 115 | + [Fact] |
| 116 | + public void CompareStructureAlignsInsertionBeforeModifiedParagraph() { |
| 117 | + string sourcePath = Path.Combine(_directoryWithFiles, "compare_structure_source_insert_before_modified.docx"); |
| 118 | + using (WordDocument doc = WordDocument.Create(sourcePath)) { |
| 119 | + doc.AddParagraph("Terms and conditions apply."); |
| 120 | + doc.AddParagraph("Closing section"); |
| 121 | + doc.Save(false); |
| 122 | + } |
| 123 | + |
| 124 | + string targetPath = Path.Combine(_directoryWithFiles, "compare_structure_target_insert_before_modified.docx"); |
| 125 | + using (WordDocument doc = WordDocument.Create(targetPath)) { |
| 126 | + doc.AddParagraph("New executive summary"); |
| 127 | + doc.AddParagraph("Terms and conditions apply after approval."); |
| 128 | + doc.AddParagraph("Closing section"); |
| 129 | + doc.Save(false); |
| 130 | + } |
| 131 | + |
| 132 | + WordComparisonResult result = WordDocumentComparer.CompareStructure(sourcePath, targetPath); |
| 133 | + |
| 134 | + Assert.Equal(2, result.Findings.Count); |
| 135 | + WordComparisonFinding inserted = Assert.Single(result.Findings, finding => |
| 136 | + finding.Scope == WordComparisonScope.Paragraph && |
| 137 | + finding.ChangeKind == WordComparisonChangeKind.Inserted); |
| 138 | + Assert.Equal("paragraph[0]", inserted.Location); |
| 139 | + Assert.Equal("New executive summary", inserted.TargetText); |
| 140 | + |
| 141 | + WordComparisonFinding modified = Assert.Single(result.Findings, finding => |
| 142 | + finding.Scope == WordComparisonScope.Paragraph && |
| 143 | + finding.ChangeKind == WordComparisonChangeKind.Modified); |
| 144 | + Assert.Equal("paragraph[1]", modified.Location); |
| 145 | + Assert.Equal("Terms and conditions apply.", modified.SourceText); |
| 146 | + Assert.Equal("Terms and conditions apply after approval.", modified.TargetText); |
| 147 | + } |
| 148 | + |
| 149 | + private static void AddBreakParagraph(WordDocument document, BreakValues breakType) { |
| 150 | + WordParagraph paragraph = document.AddParagraph("Before"); |
| 151 | + paragraph._paragraph.Append(new Run(new Break { Type = breakType })); |
| 152 | + paragraph._paragraph.Append(new Run(new Text("After"))); |
| 153 | + } |
| 154 | + |
| 155 | + private static void AddVmlImageParagraph(WordDocument document, string imagePath) { |
| 156 | + MainDocumentPart mainPart = document._wordprocessingDocument.MainDocumentPart!; |
| 157 | + ImagePart imagePart = Path.GetExtension(imagePath).Equals(".jpg", System.StringComparison.OrdinalIgnoreCase) || |
| 158 | + Path.GetExtension(imagePath).Equals(".jpeg", System.StringComparison.OrdinalIgnoreCase) |
| 159 | + ? mainPart.AddImagePart(ImagePartType.Jpeg) |
| 160 | + : mainPart.AddImagePart(ImagePartType.Png); |
| 161 | + using (FileStream stream = File.OpenRead(imagePath)) { |
| 162 | + imagePart.FeedData(stream); |
| 163 | + } |
| 164 | + |
| 165 | + string relationshipId = mainPart.GetIdOfPart(imagePart); |
| 166 | + var imageData = new V.ImageData { |
| 167 | + RelationshipId = relationshipId, |
| 168 | + Title = "Legacy image" |
| 169 | + }; |
| 170 | + var shape = new V.Shape(imageData) { |
| 171 | + Id = "LegacyImage", |
| 172 | + Type = "#_x0000_t75", |
| 173 | + Style = "width:72pt;height:72pt", |
| 174 | + Filled = false, |
| 175 | + Stroked = false |
| 176 | + }; |
| 177 | + |
| 178 | + document._document.Body!.Append(new Paragraph(new Run(new Picture(shape)))); |
| 179 | + } |
| 180 | + |
| 181 | + private static void ReplaceCellWithBlockContentControl(WordTableCell cell, string text) { |
| 182 | + cell._tableCell.RemoveAllChildren<Paragraph>(); |
| 183 | + cell._tableCell.Append(new SdtBlock( |
| 184 | + new SdtProperties(new SdtAlias { Val = "Evidence" }), |
| 185 | + new SdtContentBlock(new Paragraph(new Run(new Text(text)))))); |
| 186 | + } |
| 187 | + } |
| 188 | +} |
0 commit comments