From 5a20499263df935b6e6fcd551ebc9475f244227d Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Sat, 3 Jan 2015 09:34:07 +0000 Subject: [PATCH] Bug 53453: Apply patch to add methods to set margins in sections of HWPF documents git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1649176 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/hwpf/usermodel/Section.java | 60 ++ .../apache/poi/hwpf/usermodel/TestBugs.java | 579 +++++++++++------- test-data/document/Bug53453Section.doc | Bin 0 -> 26112 bytes 3 files changed, 415 insertions(+), 224 deletions(-) create mode 100644 test-data/document/Bug53453Section.doc diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Section.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Section.java index 4c902ee5e..4488457f8 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Section.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Section.java @@ -95,6 +95,66 @@ public final class Section extends Range return _props.getXaPage(); } + /** + * Set the height of the bottom margin in twips. In the AbstractWordUtils class, a constant + * is defined that indicates how many twips there are per inch and it can be used in setting + * the margins width a little like this; + * + * section.setMarginBottom( (int) 1.5 * AbstractWordUtils.TWIPS_PER_INCH ); + * + * @param marginWidth A primitive int whose value will indciate how high the margin should + * be - in twips. + */ + public void setMarginBottom(int marginWidth) + { + this._props.setDyaBottom(marginWidth); + } + + /** + * Set the width of the left hand margin in twips. In the AbstractWordUtils class, a constant + * is defined that indicates how many twips there are per inch and it can be used in setting + * the margins width a little like this; + * + * section.setMarginLeft( (int) 1.5 * AbstractWordUtils.TWIPS_PER_INCH ); + * + * @param marginWidth A primitive int whose value will indciate how high the margin should + * be - in twips. + */ + public void setMarginLeft(int marginWidth) + { + this._props.setDxaLeft(marginWidth); + } + + /** + * Set the width of the right hand margin in twips. In the AbstractWordUtils class, a constant + * is defined that indicates how many twips there are per inch and it can be used in setting + * the margins width a little like this; + * + * section.setMarginRight( (int) 1.5 * AbstractWordUtils.TWIPS_PER_INCH ); + * + * @param marginWidth A primitive int whose value will indciate how high the margin should + * be - in twips. + */ + public void setMarginRight(int marginWidth) + { + this._props.setDxaRight(marginWidth); + } + + /** + * Set the height of the top margin in twips. In the AbstractWordUtils class, a constant + * is defined that indicates how many twips there are per inch and it can be used in setting + * the margins width a little like this; + * + * section.setMarginTop( (int) 1.5 * AbstractWordUtils.TWIPS_PER_INCH ); + * + * @param marginWidth A primitive int whose value will indciate how high the margin should + * be - in twips. + */ + public void setMarginTop(int marginWidth) + { + this._props.setDyaTop(marginWidth); + } + public boolean isColumnsEvenlySpaced() { return _props.getFEvenlySpaced(); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java index 5f0a7ee28..3aebf1401 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestBugs.java @@ -31,6 +31,7 @@ import org.apache.poi.POIDataSamples; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.HWPFOldDocument; import org.apache.poi.hwpf.HWPFTestDataSamples; +import org.apache.poi.hwpf.converter.AbstractWordUtils; import org.apache.poi.hwpf.converter.WordToTextConverter; import org.apache.poi.hwpf.extractor.Word6Extractor; import org.apache.poi.hwpf.extractor.WordExtractor; @@ -53,80 +54,97 @@ import org.apache.poi.util.POILogger; public class TestBugs extends TestCase { private static final POILogger logger = POILogFactory - .getLogger( TestBugs.class ); + .getLogger(TestBugs.class); - public static void assertEquals( String expected, String actual ) + public static void assertEqualsIgnoreNewline(String expected, String actual ) { - String newExpected = expected.replaceAll( "\r\n", "\n" ) - .replaceAll( "\r", "\n" ).trim(); - String newActual = actual.replaceAll( "\r\n", "\n" ) - .replaceAll( "\r", "\n" ).trim(); - TestCase.assertEquals( newExpected, newActual ); + String newExpected = expected.replaceAll("\r\n", "\n" ) + .replaceAll("\r", "\n").trim(); + String newActual = actual.replaceAll("\r\n", "\n" ) + .replaceAll("\r", "\n").trim(); + TestCase.assertEquals(newExpected, newActual); } - private static void assertTableStructures( Range expected, Range actual ) + private static void assertTableStructures(Range expected, Range actual ) { - assertEquals( expected.numParagraphs(), actual.numParagraphs() ); - for ( int p = 0; p < expected.numParagraphs(); p++ ) + assertEquals(expected.numParagraphs(), actual.numParagraphs()); + for (int p = 0; p < expected.numParagraphs(); p++ ) { - Paragraph expParagraph = expected.getParagraph( p ); - Paragraph actParagraph = actual.getParagraph( p ); + Paragraph expParagraph = expected.getParagraph(p); + Paragraph actParagraph = actual.getParagraph(p); - assertEquals( expParagraph.text(), actParagraph.text() ); - assertEquals( "Diffent isInTable flags for paragraphs #" + p + assertEqualsIgnoreNewline(expParagraph.text(), actParagraph.text()); + assertEquals("Diffent isInTable flags for paragraphs #" + p + " -- " + expParagraph + " -- " + actParagraph + ".", - expParagraph.isInTable(), actParagraph.isInTable() ); - assertEquals( expParagraph.isTableRowEnd(), - actParagraph.isTableRowEnd() ); + expParagraph.isInTable(), actParagraph.isInTable()); + assertEquals(expParagraph.isTableRowEnd(), + actParagraph.isTableRowEnd()); - if ( expParagraph.isInTable() && actParagraph.isInTable() ) + if (expParagraph.isInTable() && actParagraph.isInTable() ) { Table expTable, actTable; try { - expTable = expected.getTable( expParagraph ); - actTable = actual.getTable( actParagraph ); + expTable = expected.getTable(expParagraph); + actTable = actual.getTable(actParagraph); } - catch ( Exception exc ) + catch (Exception exc ) { continue; } - assertEquals( expTable.numRows(), actTable.numRows() ); - assertEquals( expTable.numParagraphs(), - actTable.numParagraphs() ); + assertEquals(expTable.numRows(), actTable.numRows()); + assertEquals(expTable.numParagraphs(), + actTable.numParagraphs()); } } } - static void fixed( String bugzillaId ) + private static void fixed(String bugzillaId ) { throw new Error( "Bug " + bugzillaId + " seems to be fixed. " - + "Please resolve the issue in Bugzilla and remove fail() from the test" ); + + "Please resolve the issue in Bugzilla and remove fail() from the test"); + } + + private String getText(String samplefile) throws IOException { + HWPFDocument doc = HWPFTestDataSamples.openSampleFile(samplefile); + WordExtractor extractor = new WordExtractor(doc); + try { + return extractor.getText(); + } finally { + extractor.close(); + } + } + + private String getTextOldFile(String samplefile) throws IOException { + HWPFOldDocument doc = HWPFTestDataSamples.openOldSampleFile(samplefile); + Word6Extractor extractor = new Word6Extractor(doc); + try { + return extractor.getText(); + } finally { + extractor.close(); + } } /** * Bug 33519 - HWPF fails to read a file + * @throws IOException */ - public void test33519() + public void test33519() throws IOException { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug33519.doc" ); - WordExtractor extractor = new WordExtractor( doc ); - extractor.getText(); + assertNotNull(getText("Bug33519.doc")); } /** * Bug 34898 - WordExtractor doesn't read the whole string from the file + * @throws IOException */ - public void test34898() + public void test34898() throws IOException { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug34898.doc" ); - WordExtractor extractor = new WordExtractor( doc ); - assertEquals( "\u30c7\u30a3\u30ec\u30af\u30c8\u30ea", extractor - .getText().trim() ); + assertEqualsIgnoreNewline("\u30c7\u30a3\u30ec\u30af\u30c8\u30ea", getText("Bug34898.doc").trim()); } /** @@ -134,18 +152,18 @@ public class TestBugs extends TestCase */ public void test41898() { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug41898.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug41898.doc"); List pics = doc.getPicturesTable().getAllPictures(); - assertNotNull( pics ); - assertEquals( 1, pics.size() ); + assertNotNull(pics); + assertEquals(1, pics.size()); - Picture pic = pics.get( 0 ); - assertNotNull( pic.suggestFileExtension() ); - assertNotNull( pic.suggestFullFileName() ); + Picture pic = pics.get(0); + assertNotNull(pic.suggestFileExtension()); + assertNotNull(pic.suggestFullFileName()); - assertNotNull( pic.getContent() ); - assertNotNull( pic.getRawContent() ); + assertNotNull(pic.getContent()); + assertNotNull(pic.getRawContent()); /* * This is a file with empty EMF image, but present Office Drawing @@ -153,42 +171,49 @@ public class TestBugs extends TestCase */ final Collection officeDrawings = doc .getOfficeDrawingsMain().getOfficeDrawings(); - assertNotNull( officeDrawings ); - assertEquals( 1, officeDrawings.size() ); + assertNotNull(officeDrawings); + assertEquals(1, officeDrawings.size()); OfficeDrawing officeDrawing = officeDrawings.iterator().next(); - assertNotNull( officeDrawing ); - assertEquals( 1044, officeDrawing.getShapeId() ); + assertNotNull(officeDrawing); + assertEquals(1044, officeDrawing.getShapeId()); } /** * Bug 44331 - HWPFDocument.write destroys fields + * @throws IOException */ - public void test44431() + public void test44431() throws IOException { - HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile( "Bug44431.doc" ); - WordExtractor extractor1 = new WordExtractor( doc1 ); + HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("Bug44431.doc"); - HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack( doc1 ); - WordExtractor extractor2 = new WordExtractor( doc2 ); - - assertEquals( extractor1.getFooterText(), extractor2.getFooterText() ); - assertEquals( extractor1.getHeaderText(), extractor2.getHeaderText() ); - assertEquals( Arrays.toString( extractor1.getParagraphText() ), - Arrays.toString( extractor2.getParagraphText() ) ); - - assertEquals( extractor1.getText(), extractor2.getText() ); + WordExtractor extractor1 = new WordExtractor(doc1); + try { + HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack(doc1); + + WordExtractor extractor2 = new WordExtractor(doc2); + try { + assertEqualsIgnoreNewline(extractor1.getFooterText(), extractor2.getFooterText()); + assertEqualsIgnoreNewline(extractor1.getHeaderText(), extractor2.getHeaderText()); + assertEqualsIgnoreNewline(Arrays.toString(extractor1.getParagraphText() ), + Arrays.toString(extractor2.getParagraphText())); + + assertEqualsIgnoreNewline(extractor1.getText(), extractor2.getText()); + } finally { + extractor2.close(); + } + } finally { + extractor1.close(); + } } /** * Bug 44331 - HWPFDocument.write destroys fields + * @throws IOException */ - public void test44431_2() + public void test44431_2() throws IOException { - HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile( "Bug44431.doc" ); - WordExtractor extractor1 = new WordExtractor( doc1 ); - - assertEquals( "File name=FieldsTest.doc\n" + + assertEqualsIgnoreNewline("File name=FieldsTest.doc\n" + "\n" + "\n" + "STYLEREF test\n" + @@ -207,23 +232,36 @@ public class TestBugs extends TestCase "\n" + "\n" + "\n" + - "Page 3 of 3", extractor1.getText() ); + "Page 3 of 3", getText("Bug44431.doc")); } /** * Bug 45473 - HWPF cannot read file after save + * @throws IOException */ - public void test45473() + public void test45473() throws IOException { - HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile( "Bug45473.doc" ); - String text1 = new WordExtractor( doc1 ).getText().trim(); + HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("Bug45473.doc"); + WordExtractor wordExtractor = new WordExtractor(doc1); + final String text1; + try { + text1 = wordExtractor.getText().trim(); + } finally { + wordExtractor.close(); + } - HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack( doc1 ); - String text2 = new WordExtractor( doc2 ).getText().trim(); + HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack(doc1); + WordExtractor wordExtractor2 = new WordExtractor(doc2); + final String text2; + try { + text2 = wordExtractor2.getText().trim(); + } finally { + wordExtractor2.close(); + } // the text in the saved document has some differences in line // separators but we tolerate that - assertEquals( text1.replaceAll( "\n", "" ), text2.replaceAll( "\n", "" ) ); + assertEqualsIgnoreNewline(text1.replaceAll("\n", "" ), text2.replaceAll("\n", "")); } /** @@ -231,36 +269,35 @@ public class TestBugs extends TestCase */ public void test46220() { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug46220.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug46220.doc"); // reference checksums as in Bugzilla String[] md5 = { "851be142bce6d01848e730cb6903f39e", "7fc6d8fb58b09ababd036d10a0e8c039", "a7dc644c40bc2fbf17b2b62d07f99248", "72d07b8db5fad7099d90bc4c304b4666" }; List pics = doc.getPicturesTable().getAllPictures(); - assertEquals( 4, pics.size() ); - for ( int i = 0; i < pics.size(); i++ ) + assertEquals(4, pics.size()); + for (int i = 0; i < pics.size(); i++ ) { - Picture pic = pics.get( i ); + Picture pic = pics.get(i); byte[] data = pic.getRawContent(); // use Apache Commons Codec utils to compute md5 - assertEquals( md5[i], DigestUtils.md5Hex( data ) ); + assertEqualsIgnoreNewline(md5[i], DigestUtils.md5Hex(data)); } } /** * [RESOLVED FIXED] Bug 46817 - Regression: Text from some table cells * missing + * @throws IOException */ - public void test46817() + public void test46817() throws IOException { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug46817.doc" ); - WordExtractor extractor = new WordExtractor( doc ); - String text = extractor.getText().trim(); + String text = getText("Bug46817.doc").trim(); - assertTrue( text.contains( "Nazwa wykonawcy" ) ); - assertTrue( text.contains( "kujawsko-pomorskie" ) ); - assertTrue( text.contains( "ekomel@ekomel.com.pl" ) ); + assertTrue(text.contains("Nazwa wykonawcy")); + assertTrue(text.contains("kujawsko-pomorskie")); + assertTrue(text.contains("ekomel@ekomel.com.pl")); } /** @@ -271,26 +308,38 @@ public class TestBugs extends TestCase */ public void test47286() throws IOException { - HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile( "Bug47286.doc" ); - String text1 = new WordExtractor( doc1 ).getText().trim(); + HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("Bug47286.doc"); + WordExtractor wordExtractor = new WordExtractor(doc1); + final String text1; + try { + text1 = wordExtractor.getText().trim(); + } finally { + wordExtractor.close(); + } - HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack( doc1 ); - String text2 = new WordExtractor( doc2 ).getText().trim(); + HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack(doc1); + WordExtractor wordExtractor2 = new WordExtractor(doc2); + final String text2; + try { + text2 = wordExtractor2.getText().trim(); + } finally { + wordExtractor2.close(); + } // the text in the saved document has some differences in line // separators but we tolerate that - assertEquals( text1.replaceAll( "\n", "" ), text2.replaceAll( "\n", "" ) ); + assertEqualsIgnoreNewline(text1.replaceAll("\n", "" ), text2.replaceAll("\n", "")); - assertEquals( doc1.getCharacterTable().getTextRuns().size(), doc2 - .getCharacterTable().getTextRuns().size() ); + assertEquals(doc1.getCharacterTable().getTextRuns().size(), doc2 + .getCharacterTable().getTextRuns().size()); List expectedFields = doc1.getFieldsTables() - .getFieldsPLCF( FieldsDocumentPart.MAIN ); + .getFieldsPLCF(FieldsDocumentPart.MAIN); List actualFields = doc2.getFieldsTables().getFieldsPLCF( - FieldsDocumentPart.MAIN ); - assertEquals( expectedFields.size(), actualFields.size() ); + FieldsDocumentPart.MAIN); + assertEquals(expectedFields.size(), actualFields.size()); - assertTableStructures( doc1.getRange(), doc2.getRange() ); + assertTableStructures(doc1.getRange(), doc2.getRange()); } /** @@ -299,60 +348,60 @@ public class TestBugs extends TestCase */ public void test47287() { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug47287.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug47287.doc"); String[] values = { "1-1", "1-2", "1-3", "1-4", "1-5", "1-6", "1-7", "1-8", "1-9", "1-10", "1-11", "1-12", "1-13", "1-14", "1-15", }; int usedVal = 0; String PLACEHOLDER = "\u2002\u2002\u2002\u2002\u2002"; Range r = doc.getRange(); - for ( int x = 0; x < r.numSections(); x++ ) + for (int x = 0; x < r.numSections(); x++ ) { - Section s = r.getSection( x ); - for ( int y = 0; y < s.numParagraphs(); y++ ) + Section s = r.getSection(x); + for (int y = 0; y < s.numParagraphs(); y++ ) { - Paragraph p = s.getParagraph( y ); + Paragraph p = s.getParagraph(y); - for ( int z = 0; z < p.numCharacterRuns(); z++ ) + for (int z = 0; z < p.numCharacterRuns(); z++ ) { boolean isFound = false; // character run - CharacterRun run = p.getCharacterRun( z ); + CharacterRun run = p.getCharacterRun(z); // character run text String text = run.text(); String oldText = text; - int c = text.indexOf( "FORMTEXT " ); - if ( c < 0 ) + int c = text.indexOf("FORMTEXT "); + if (c < 0 ) { - int k = text.indexOf( PLACEHOLDER ); - if ( k >= 0 ) + int k = text.indexOf(PLACEHOLDER); + if (k >= 0 ) { - text = text.substring( 0, k ) + values[usedVal] - + text.substring( k + PLACEHOLDER.length() ); + text = text.substring(0, k ) + values[usedVal] + + text.substring(k + PLACEHOLDER.length()); usedVal++; isFound = true; } } else { - for ( ; c >= 0; c = text.indexOf( "FORMTEXT ", c + for (; c >= 0; c = text.indexOf("FORMTEXT ", c + "FORMTEXT ".length() ) ) { - int k = text.indexOf( PLACEHOLDER, c ); - if ( k >= 0 ) + int k = text.indexOf(PLACEHOLDER, c); + if (k >= 0 ) { - text = text.substring( 0, k ) + text = text.substring(0, k ) + values[usedVal] - + text.substring( k - + PLACEHOLDER.length() ); + + text.substring(k + + PLACEHOLDER.length()); usedVal++; isFound = true; } } } - if ( isFound ) + if (isFound ) { - run.replaceText( oldText, text, 0 ); + run.replaceText(oldText, text, 0); } } @@ -361,11 +410,11 @@ public class TestBugs extends TestCase String docText = r.text(); - assertTrue( docText.contains( "1-1" ) ); - assertTrue( docText.contains( "1-12" ) ); + assertTrue(docText.contains("1-1")); + assertTrue(docText.contains("1-12")); - assertFalse( docText.contains( "1-13" ) ); - assertFalse( docText.contains( "1-15" ) ); + assertFalse(docText.contains("1-13")); + assertFalse(docText.contains("1-15")); } /** @@ -374,11 +423,10 @@ public class TestBugs extends TestCase */ public void test47731() throws Exception { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug47731.doc" ); - String foundText = new WordExtractor( doc ).getText(); + String foundText = getText("Bug47731.doc"); - assertTrue( foundText - .contains( "Soak the rice in water for three to four hours" ) ); + assertTrue(foundText + .contains("Soak the rice in water for three to four hours")); } /** @@ -386,21 +434,19 @@ public class TestBugs extends TestCase */ public void test47742() throws Exception { - // (1) extract text from MS Word document via POI - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug47742.doc" ); - String foundText = new WordExtractor( doc ).getText(); + String foundText = getText("Bug47742.doc"); // (2) read text from text document (retrieved by saving the word // document as text file using encoding UTF-8) InputStream is = POIDataSamples.getDocumentInstance() - .openResourceAsStream( "Bug47742-text.txt" ); + .openResourceAsStream("Bug47742-text.txt"); try { - byte[] expectedBytes = IOUtils.toByteArray( is ); - String expectedText = new String( expectedBytes, "utf-8" ) - .substring( 1 ); // strip-off the unicode marker + byte[] expectedBytes = IOUtils.toByteArray(is); + String expectedText = new String(expectedBytes, "utf-8" ) + .substring(1); // strip-off the unicode marker - assertEquals( expectedText, foundText ); + assertEqualsIgnoreNewline(expectedText, foundText); } finally { is.close(); } @@ -411,7 +457,7 @@ public class TestBugs extends TestCase */ public void test47958() { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug47958.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug47958.doc"); doc.getPicturesTable().getAllPictures(); } @@ -421,26 +467,22 @@ public class TestBugs extends TestCase */ public void test48065() { - HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile( "Bug48065.doc" ); - HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack( doc1 ); + HWPFDocument doc1 = HWPFTestDataSamples.openSampleFile("Bug48065.doc"); + HWPFDocument doc2 = HWPFTestDataSamples.writeOutAndReadBack(doc1); Range expected = doc1.getRange(); Range actual = doc2.getRange(); - assertEquals( - expected.text().replace( "\r", "\n" ).replaceAll( "\n\n", "\n" ), - actual.text().replace( "\r", "\n" ).replaceAll( "\n\n", "\n" ) ); + assertEqualsIgnoreNewline( + expected.text().replace("\r", "\n").replaceAll("\n\n", "\n" ), + actual.text().replace("\r", "\n").replaceAll("\n\n", "\n")); - assertTableStructures( expected, actual ); + assertTableStructures(expected, actual); } - public void test49933() + public void test49933() throws IOException { - HWPFOldDocument document = HWPFTestDataSamples - .openOldSampleFile( "Bug49933.doc" ); - - Word6Extractor word6Extractor = new Word6Extractor( document ); - String text = word6Extractor.getText(); + String text = getTextOldFile("Bug49933.doc"); assertTrue( text.contains( "best.wine.jump.ru" ) ); } @@ -451,7 +493,7 @@ public class TestBugs extends TestCase public void test50936_1() { HWPFDocument hwpfDocument = HWPFTestDataSamples - .openSampleFile( "Bug50936_1.doc" ); + .openSampleFile("Bug50936_1.doc"); hwpfDocument.getPicturesTable().getAllPictures(); } @@ -461,7 +503,7 @@ public class TestBugs extends TestCase public void test50936_2() { HWPFDocument hwpfDocument = HWPFTestDataSamples - .openSampleFile( "Bug50936_2.doc" ); + .openSampleFile("Bug50936_2.doc"); hwpfDocument.getPicturesTable().getAllPictures(); } @@ -471,61 +513,56 @@ public class TestBugs extends TestCase public void test50936_3() { HWPFDocument hwpfDocument = HWPFTestDataSamples - .openSampleFile( "Bug50936_3.doc" ); + .openSampleFile("Bug50936_3.doc"); hwpfDocument.getPicturesTable().getAllPictures(); } /** * [FAILING] Bug 50955 - error while retrieving the text file + * @throws IOException */ - public void test50955() + public void test50955() throws IOException { - try - { - HWPFOldDocument doc = HWPFTestDataSamples - .openOldSampleFile( "Bug50955.doc" ); - Word6Extractor extractor = new Word6Extractor( doc ); - extractor.getText(); + try { + getTextOldFile("Bug50955.doc"); - fixed( "50955" ); - } - catch ( Exception e ) - { - // expected exception + fixed("50955"); + } catch (IllegalStateException e) { + // expected here } } /** - * [RESOLVED FIXED] Bug 51604 - replace text fails for doc ( poi 3.8 beta + * [RESOLVED FIXED] Bug 51604 - replace text fails for doc (poi 3.8 beta * release from download site ) */ public void test51604() { HWPFDocument document = HWPFTestDataSamples - .openSampleFile( "Bug51604.doc" ); + .openSampleFile("Bug51604.doc"); Range range = document.getRange(); int numParagraph = range.numParagraphs(); int counter = 0; - for ( int i = 0; i < numParagraph; i++ ) + for (int i = 0; i < numParagraph; i++ ) { - Paragraph paragraph = range.getParagraph( i ); + Paragraph paragraph = range.getParagraph(i); int numCharRuns = paragraph.numCharacterRuns(); - for ( int j = 0; j < numCharRuns; j++ ) + for (int j = 0; j < numCharRuns; j++ ) { - CharacterRun charRun = paragraph.getCharacterRun( j ); + CharacterRun charRun = paragraph.getCharacterRun(j); String text = charRun.text(); - charRun.replaceText( text, "+" + ( ++counter ) ); + charRun.replaceText(text, "+" + (++counter)); } } - document = HWPFTestDataSamples.writeOutAndReadBack( document ); + document = HWPFTestDataSamples.writeOutAndReadBack(document); String text = document.getDocumentText(); - assertEquals( "+1+2+3+4+5+6+7+8+9+10+11+12", text ); + assertEqualsIgnoreNewline("+1+2+3+4+5+6+7+8+9+10+11+12", text); } /** - * [RESOLVED FIXED] Bug 51604 - replace text fails for doc ( poi 3.8 beta + * [RESOLVED FIXED] Bug 51604 - replace text fails for doc (poi 3.8 beta * release from download site ) * * @throws IOException @@ -533,81 +570,81 @@ public class TestBugs extends TestCase */ public void test51604p2() throws Exception { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug51604.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug51604.doc"); Range range = doc.getRange(); int numParagraph = range.numParagraphs(); - for ( int i = 0; i < numParagraph; i++ ) + for (int i = 0; i < numParagraph; i++ ) { - Paragraph paragraph = range.getParagraph( i ); + Paragraph paragraph = range.getParagraph(i); int numCharRuns = paragraph.numCharacterRuns(); - for ( int j = 0; j < numCharRuns; j++ ) + for (int j = 0; j < numCharRuns; j++ ) { - CharacterRun charRun = paragraph.getCharacterRun( j ); + CharacterRun charRun = paragraph.getCharacterRun(j); String text = charRun.text(); - if ( text.contains( "Header" ) ) - charRun.replaceText( text, "added" ); + if (text.contains("Header" ) ) + charRun.replaceText(text, "added"); } } - doc = HWPFTestDataSamples.writeOutAndReadBack( doc ); + doc = HWPFTestDataSamples.writeOutAndReadBack(doc); final FileInformationBlock fileInformationBlock = doc .getFileInformationBlock(); int totalLength = 0; - for ( SubdocumentType type : SubdocumentType.values() ) + for (SubdocumentType type : SubdocumentType.values() ) { final int partLength = fileInformationBlock - .getSubdocumentTextStreamLength( type ); - assert ( partLength >= 0 ); + .getSubdocumentTextStreamLength(type); + assert (partLength >= 0); totalLength += partLength; } - assertEquals( doc.getText().length(), totalLength ); + assertEquals(doc.getText().length(), totalLength); } /** - * [RESOLVED FIXED] Bug 51604 - replace text fails for doc ( poi 3.8 beta + * [RESOLVED FIXED] Bug 51604 - replace text fails for doc (poi 3.8 beta * release from download site ) */ public void test51604p3() throws Exception { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug51604.doc" ); + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug51604.doc"); byte[] originalData = new byte[doc.getFileInformationBlock() .getLcbDop()]; - System.arraycopy( doc.getTableStream(), doc.getFileInformationBlock() - .getFcDop(), originalData, 0, originalData.length ); + System.arraycopy(doc.getTableStream(), doc.getFileInformationBlock() + .getFcDop(), originalData, 0, originalData.length); HWPFOutputStream outputStream = new HWPFOutputStream(); - doc.getDocProperties().writeTo( outputStream ); + doc.getDocProperties().writeTo(outputStream); final byte[] oldData = outputStream.toByteArray(); - assertEquals( Arrays.toString( originalData ), - Arrays.toString( oldData ) ); + assertEqualsIgnoreNewline(Arrays.toString(originalData ), + Arrays.toString(oldData)); Range range = doc.getRange(); int numParagraph = range.numParagraphs(); - for ( int i = 0; i < numParagraph; i++ ) + for (int i = 0; i < numParagraph; i++ ) { - Paragraph paragraph = range.getParagraph( i ); + Paragraph paragraph = range.getParagraph(i); int numCharRuns = paragraph.numCharacterRuns(); - for ( int j = 0; j < numCharRuns; j++ ) + for (int j = 0; j < numCharRuns; j++ ) { - CharacterRun charRun = paragraph.getCharacterRun( j ); + CharacterRun charRun = paragraph.getCharacterRun(j); String text = charRun.text(); - if ( text.contains( "Header" ) ) - charRun.replaceText( text, "added" ); + if (text.contains("Header" ) ) + charRun.replaceText(text, "added"); } } - doc = HWPFTestDataSamples.writeOutAndReadBack( doc ); + doc = HWPFTestDataSamples.writeOutAndReadBack(doc); outputStream = new HWPFOutputStream(); - doc.getDocProperties().writeTo( outputStream ); + doc.getDocProperties().writeTo(outputStream); final byte[] newData = outputStream.toByteArray(); - assertEquals( Arrays.toString( oldData ), Arrays.toString( newData ) ); + assertEqualsIgnoreNewline(Arrays.toString(oldData ), Arrays.toString(newData)); } /** @@ -617,30 +654,39 @@ public class TestBugs extends TestCase public void test51671() throws Exception { InputStream is = POIDataSamples.getDocumentInstance() - .openResourceAsStream( "empty.doc" ); - NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem( is ); - HWPFDocument hwpfDocument = new HWPFDocument( - npoifsFileSystem.getRoot() ); - hwpfDocument.write( new ByteArrayOutputStream() ); + .openResourceAsStream("empty.doc"); + NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem(is); + try { + HWPFDocument hwpfDocument = new HWPFDocument( + npoifsFileSystem.getRoot()); + hwpfDocument.write(new ByteArrayOutputStream()); + } finally { + npoifsFileSystem.close(); + } } /** * Bug 51678 - Extracting text from Bug51524.zip is slow Bug 51524 - * PapBinTable constructor is slow + * @throws IOException */ - public void test51678And51524() + public void test51678And51524() throws IOException { // YK: the test will run only if the poi.test.remote system property is // set. // TODO: refactor into something nicer! - if ( System.getProperty( "poi.test.remote" ) != null ) + if (System.getProperty("poi.test.remote" ) != null ) { String href = "http://domex.nps.edu/corp/files/govdocs1/007/007488.doc"; HWPFDocument hwpfDocument = HWPFTestDataSamples - .openRemoteFile( href ); + .openRemoteFile(href); - WordExtractor wordExtractor = new WordExtractor( hwpfDocument ); - wordExtractor.getText(); + WordExtractor wordExtractor = new WordExtractor(hwpfDocument); + try { + wordExtractor.getText(); + } finally { + wordExtractor.close(); + } } } @@ -650,13 +696,13 @@ public class TestBugs extends TestCase */ public void testBug51890() { - HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug51890.doc" ); - for ( Picture picture : doc.getPicturesTable().getAllPictures() ) + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("Bug51890.doc"); + for (Picture picture : doc.getPicturesTable().getAllPictures() ) { PictureType pictureType = picture.suggestPictureType(); - logger.log( POILogger.DEBUG, + logger.log(POILogger.DEBUG, "Picture at offset " + picture.getStartOffset() - + " has type " + pictureType ); + + " has type " + pictureType); } } @@ -670,9 +716,9 @@ public class TestBugs extends TestCase * we don't have Java test for this file - it should be checked using * Microsoft BFF Validator. But check read-write-read anyway. -- sergey */ - HWPFTestDataSamples.openSampleFile( "Bug51834.doc" ); - HWPFTestDataSamples.writeOutAndReadBack( HWPFTestDataSamples - .openSampleFile( "Bug51834.doc" ) ); + HWPFTestDataSamples.openSampleFile("Bug51834.doc"); + HWPFTestDataSamples.writeOutAndReadBack(HWPFTestDataSamples + .openSampleFile("Bug51834.doc")); } /** @@ -680,8 +726,8 @@ public class TestBugs extends TestCase */ public void testBug51944() throws Exception { - HWPFOldDocument doc = HWPFTestDataSamples.openOldSampleFile( "Bug51944.doc" ); - WordToTextConverter.getText( doc ); + HWPFOldDocument doc = HWPFTestDataSamples.openOldSampleFile("Bug51944.doc"); + assertNotNull(WordToTextConverter.getText(doc)); } /** @@ -690,7 +736,7 @@ public class TestBugs extends TestCase */ public void testBug52032_1() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug52032_1.doc" ); + assertNotNull(getText("Bug52032_1.doc")); } /** @@ -699,7 +745,7 @@ public class TestBugs extends TestCase */ public void testBug52032_2() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug52032_2.doc" ); + assertNotNull(getText("Bug52032_2.doc")); } /** @@ -708,7 +754,7 @@ public class TestBugs extends TestCase */ public void testBug52032_3() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug52032_3.doc" ); + assertNotNull(getText("Bug52032_3.doc")); } /** @@ -716,7 +762,7 @@ public class TestBugs extends TestCase */ public void testBug53380_1() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug53380_1.doc" ); + assertNotNull(getText("Bug53380_1.doc")); } /** @@ -724,7 +770,7 @@ public class TestBugs extends TestCase */ public void testBug53380_2() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug53380_2.doc" ); + assertNotNull(getText("Bug53380_2.doc")); } /** @@ -732,7 +778,7 @@ public class TestBugs extends TestCase */ public void testBug53380_3() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug53380_3.doc" ); + assertNotNull(getText("Bug53380_3.doc")); } /** @@ -740,7 +786,7 @@ public class TestBugs extends TestCase */ public void testBug53380_4() throws Exception { - HWPFTestDataSamples.openSampleFile( "Bug53380_4.doc" ); + assertNotNull(getText("Bug53380_4.doc")); } /** @@ -752,6 +798,91 @@ public class TestBugs extends TestCase public void DISABLEDtest56880() throws Exception { HWPFDocument doc = HWPFTestDataSamples.openSampleFile("56880.doc"); - assertEquals("Check Request", doc.getRange().text()); + assertEqualsIgnoreNewline("Check Request", doc.getRange().text()); + } + + + // These are the values the are explected to be read when the file + // is checked. + private int section1LeftMargin = 1440; + private int section1RightMargin = 1440; + private int section1TopMargin = 1440; + private int section1BottomMargin = 1440; + private int section1NumColumns = 1; + private int section2LeftMargin = 1440; + private int section2RightMargin = 1440; + private int section2TopMargin = 1440; + private int section2BottomMargin = 1440; + private int section2NumColumns = 3; + + public void testHWPFSections() { + HWPFDocument document = null; + Paragraph para = null; + Section section = null; + Range overallRange = null; + int numParas = 0; + int numSections = 0; + document = HWPFTestDataSamples.openSampleFile("Bug53453Section.doc"); + overallRange = document.getOverallRange(); + numParas = overallRange.numParagraphs(); + for(int i = 0; i < numParas; i++) { + para = overallRange.getParagraph(i); + numSections = para.numSections(); + for(int j = 0; j < numSections; j++) { + section = para.getSection(j); + if(para.text().trim().equals("Section1")) { + assertEquals(section1BottomMargin, section.getMarginBottom()); + assertEquals(section1LeftMargin, section.getMarginLeft()); + assertEquals(section1RightMargin, section.getMarginRight()); + assertEquals(section1TopMargin, section.getMarginTop()); + assertEquals(section1NumColumns, section.getNumColumns()); + } + else if(para.text().trim().equals("Section2")) { + assertEquals(section2BottomMargin, section.getMarginBottom()); + assertEquals(section2LeftMargin, section.getMarginLeft()); + assertEquals(section2RightMargin, section.getMarginRight()); + assertEquals(section2TopMargin, section.getMarginTop()); + assertEquals(section2NumColumns, section.getNumColumns()); + + // Change the margin widths + this.section2BottomMargin = (int)(1.5 * AbstractWordUtils.TWIPS_PER_INCH); + this.section2TopMargin = (int)(1.75 * AbstractWordUtils.TWIPS_PER_INCH); + this.section2LeftMargin = (int)(0.5 * AbstractWordUtils.TWIPS_PER_INCH); + this.section2RightMargin = (int)(0.75 * AbstractWordUtils.TWIPS_PER_INCH); + section.setMarginBottom(this.section2BottomMargin); + section.setMarginLeft(this.section2LeftMargin); + section.setMarginRight(this.section2RightMargin); + section.setMarginTop(this.section2TopMargin); + } + } + } + + // Save away and re-read the document to prove the chages are permanent + document = HWPFTestDataSamples.writeOutAndReadBack(document); + overallRange = document.getOverallRange(); + numParas = overallRange.numParagraphs(); + for(int i = 0; i < numParas; i++) { + para = overallRange.getParagraph(i); + numSections = para.numSections(); + for(int j = 0; j < numSections; j++) { + section = para.getSection(j); + if(para.text().trim().equals("Section1")) { + // No changes to the margins in Section1 + assertEquals(section1BottomMargin, section.getMarginBottom()); + assertEquals(section1LeftMargin, section.getMarginLeft()); + assertEquals(section1RightMargin, section.getMarginRight()); + assertEquals(section1TopMargin, section.getMarginTop()); + assertEquals(section1NumColumns, section.getNumColumns()); + } + else if(para.text().trim().equals("Section2")) { + // The margins in Section2 have kept the new settings. + assertEquals(section2BottomMargin, section.getMarginBottom()); + assertEquals(section2LeftMargin, section.getMarginLeft()); + assertEquals(section2RightMargin, section.getMarginRight()); + assertEquals(section2TopMargin, section.getMarginTop()); + assertEquals(section2NumColumns, section.getNumColumns()); + } + } + } } } diff --git a/test-data/document/Bug53453Section.doc b/test-data/document/Bug53453Section.doc new file mode 100644 index 0000000000000000000000000000000000000000..23275b6d878fac7d28f6fc631b2595778b240646 GIT binary patch literal 26112 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