From: Yegor Kozlov Date: Sat, 27 Nov 2010 06:30:03 +0000 (+0000) Subject: improved LinkTable to support registering external UDFs. X-Git-Tag: REL_3_8_BETA1~111 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fa5be6e8200341ea237244b2eccd203ff3f6886d;p=poi.git improved LinkTable to support registering external UDFs. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1039621 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java index c047f2f0cd..12bd39d633 100644 --- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java +++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java @@ -83,6 +83,7 @@ import org.apache.poi.hssf.record.WriteProtectRecord; import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.ss.formula.ptg.NameXPtg; import org.apache.poi.ss.formula.FormulaShifter; +import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName; @@ -2300,8 +2301,22 @@ public final class InternalWorkbook { return linkTable.resolveNameXText(refIndex, definedNameIndex); } - public NameXPtg getNameXPtg(String name) { - return getOrCreateLinkTable().getNameXPtg(name); + /** + * + * @param name the name of an external function, typically a name of a UDF + * @param udf locator of user-defiend functions to resolve names of VBA and Add-In functions + * @return the external name or null + */ + public NameXPtg getNameXPtg(String name, UDFFinder udf) { + LinkTable lnk = getOrCreateLinkTable(); + NameXPtg xptg = lnk.getNameXPtg(name); + + if(xptg == null && udf.findFunction(name) != null) { + // the name was not found in the list of external names + // check if the Workbook's UDFFinder is aware about it and register the name if it is + xptg = lnk.addNameXPtg(name); + } + return xptg; } /** diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index e92213899c..732ab14803 100644 --- a/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -31,9 +31,7 @@ import org.apache.poi.hssf.record.NameCommentRecord; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SupBookRecord; -import org.apache.poi.ss.formula.ptg.Area3DPtg; -import org.apache.poi.ss.formula.ptg.NameXPtg; -import org.apache.poi.ss.formula.ptg.Ref3DPtg; +import org.apache.poi.ss.formula.ptg.*; /** * Link Table (OOO pdf reference: 4.10.3 )

@@ -92,7 +90,7 @@ final class LinkTable { private static final class ExternalBookBlock { private final SupBookRecord _externalBookRecord; - private final ExternalNameRecord[] _externalNameRecords; + private ExternalNameRecord[] _externalNameRecords; private final CRNBlock[] _crnBlocks; public ExternalBookBlock(RecordStream rs) { @@ -113,12 +111,28 @@ final class LinkTable { temp.toArray(_crnBlocks); } - public ExternalBookBlock(int numberOfSheets) { + /** + * Create a new block for internal references. It is called when constructing a new LinkTable. + * + * @see org.apache.poi.hssf.model.LinkTable#LinkTable(int, WorkbookRecordList) + */ + public ExternalBookBlock(int numberOfSheets) { _externalBookRecord = SupBookRecord.createInternalReferences((short)numberOfSheets); _externalNameRecords = new ExternalNameRecord[0]; _crnBlocks = new CRNBlock[0]; } + /** + * Create a new block for registering add-in functions + * + * @see org.apache.poi.hssf.model.LinkTable#addNameXPtg(String) + */ + public ExternalBookBlock() { + _externalBookRecord = SupBookRecord.createAddInFunctions(); + _externalNameRecords = new ExternalNameRecord[0]; + _crnBlocks = new CRNBlock[0]; + } + public SupBookRecord getExternalBookRecord() { return _externalBookRecord; } @@ -143,9 +157,21 @@ final class LinkTable { } return -1; } - } - private final ExternalBookBlock[] _externalBookBlocks; + public int getNumberOfNames() { + return _externalNameRecords.length; + } + + public int addExternalName(ExternalNameRecord rec){ + ExternalNameRecord[] tmp = new ExternalNameRecord[_externalNameRecords.length + 1]; + System.arraycopy(_externalNameRecords, 0, tmp, 0, _externalNameRecords.length); + tmp[tmp.length - 1] = rec; + _externalNameRecords = tmp; + return _externalNameRecords.length - 1; + } + } + + private ExternalBookBlock[] _externalBookBlocks; private final ExternSheetRecord _externSheetRecord; private final List _definedNames; private final int _recordCount; @@ -461,7 +487,69 @@ final class LinkTable { return null; } - private int findRefIndexFromExtBookIndex(int extBookIndex) { + /** + * Register an external name in this workbook + * + * @param name the name to register + * @return a NameXPtg describing this name + */ + public NameXPtg addNameXPtg(String name) { + int extBlockIndex = -1; + ExternalBookBlock extBlock = null; + + // find ExternalBlock for Add-In functions and remember its index + for (int i = 0; i < _externalBookBlocks.length; i++) { + SupBookRecord ebr = _externalBookBlocks[i].getExternalBookRecord(); + if (ebr.isAddInFunctions()) { + extBlock = _externalBookBlocks[i]; + extBlockIndex = i; + break; + } + } + // An ExternalBlock for Add-In functions was not found. Create a new one. + if (extBlock == null) { + extBlock = new ExternalBookBlock(); + + ExternalBookBlock[] tmp = new ExternalBookBlock[_externalBookBlocks.length + 1]; + System.arraycopy(_externalBookBlocks, 0, tmp, 0, _externalBookBlocks.length); + tmp[tmp.length - 1] = extBlock; + _externalBookBlocks = tmp; + + extBlockIndex = _externalBookBlocks.length - 1; + + // add the created SupBookRecord before ExternSheetRecord + int idx = findFirstRecordLocBySid(ExternSheetRecord.sid); + _workbookRecordList.add(idx, extBlock.getExternalBookRecord()); + + // register the SupBookRecord in the ExternSheetRecord + // -2 means that the scope of this name is Workbook and the reference applies to the entire workbook. + _externSheetRecord.addRef(_externalBookBlocks.length - 1, -2, -2); + } + + // create a ExternalNameRecord that will describe this name + ExternalNameRecord extNameRecord = new ExternalNameRecord(); + extNameRecord.setText(name); + // The docs don't explain why Excel set the formula to #REF! + extNameRecord.setParsedExpression(new Ptg[]{ErrPtg.REF_INVALID}); + + int nameIndex = extBlock.addExternalName(extNameRecord); + int supLinkIndex = 0; + // find the posistion of the Add-In SupBookRecord in the workbook stream, + // the created ExternalNameRecord will be appended to it + for (Iterator iterator = _workbookRecordList.iterator(); iterator.hasNext(); supLinkIndex++) { + Record record = (Record) iterator.next(); + if (record instanceof SupBookRecord) { + if (((SupBookRecord) record).isAddInFunctions()) break; + } + } + int numberOfNames = extBlock.getNumberOfNames(); + // a new name is inserted in the end of the SupBookRecord, after the last name + _workbookRecordList.add(supLinkIndex + numberOfNames, extNameRecord); + int ix = _externSheetRecord.getRefIxForSheet(extBlockIndex, -2 /* the scope is workbook*/); + return new NameXPtg(ix, nameIndex); + } + + private int findRefIndexFromExtBookIndex(int extBookIndex) { return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex); } } diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java index 0999b2cdc0..963e325ab9 100644 --- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java @@ -29,7 +29,8 @@ import org.apache.poi.util.LittleEndianOutput; * @author Libin Roman (Vista Portal LDT. Developer) */ public class ExternSheetRecord extends StandardRecord { - public final static short sid = 0x0017; + + public final static short sid = 0x0017; private List _list; private static final class RefSubRecord { @@ -184,6 +185,33 @@ public class ExternSheetRecord extends StandardRecord { } /** + * Add a zero-based reference to a {@link org.apache.poi.hssf.record.SupBookRecord}. + *

+ * If the type of the SupBook record is same-sheet referencing, Add-In referencing, + * DDE data source referencing, or OLE data source referencing, + * then no scope is specified and this value MUST be -2. Otherwise, + * the scope must be set as follows: + *

    + *
  1. -2 Workbook-level reference that applies to the entire workbook.
  2. + *
  3. -1 Sheet-level reference.
  4. + *
  5. >=0 Sheet-level reference. This specifies the first sheet in the reference. + *

    + * If the SupBook type is unused or external workbook referencing, + * then this value specifies the zero-based index of an external sheet name, + * see {@link org.apache.poi.hssf.record.SupBookRecord#getSheetNames()}. + * This referenced string specifies the name of the first sheet within the external workbook that is in scope. + * This sheet MUST be a worksheet or macro sheet. + *

    + *

    + * If the supporting link type is self-referencing, then this value specifies the zero-based index of a + * {@link org.apache.poi.hssf.record.BoundSheetRecord} record in the workbook stream that specifies + * the first sheet within the scope of this reference. This sheet MUST be a worksheet or a macro sheet. + *

    + *
  6. + *
+ * + * @param firstSheetIndex the scope, must be -2 for add-in references + * @param lastSheetIndex the scope, must be -2 for add-in references * @return index of newly added ref */ public int addRef(int extBookIndex, int firstSheetIndex, int lastSheetIndex) { diff --git a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java index fc2e4c1da8..cb1c5ac25b 100644 --- a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.record; import org.apache.poi.ss.formula.constant.ConstantValueParser; import org.apache.poi.ss.formula.Formula; +import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; @@ -98,6 +99,10 @@ public final class ExternalNameRecord extends StandardRecord { return field_4_name; } + public void setText(String str) { + field_4_name = str; + } + /** * If this is a local name, then this is the (1 based) * index of the name of the Sheet this refers to, as @@ -107,6 +112,17 @@ public final class ExternalNameRecord extends StandardRecord { public short getIx() { return field_2_ixals; } + public void setIx(short ix) { + field_2_ixals = ix; + } + + public Ptg[] getParsedExpression() { + return Formula.getTokens(field_5_name_definition); + } + public void setParsedExpression(Ptg[] ptgs) { + field_5_name_definition = Formula.create(ptgs); + } + protected int getDataSize(){ int result = 2 + 4; // short and int @@ -142,8 +158,11 @@ public final class ExternalNameRecord extends StandardRecord { } } - - public ExternalNameRecord(RecordInputStream in) { + public ExternalNameRecord() { + field_2_ixals = 0; + } + + public ExternalNameRecord(RecordInputStream in) { field_1_option_flag = in.readShort(); field_2_ixals = in.readShort(); field_3_not_used = in.readShort(); @@ -180,10 +199,15 @@ public final class ExternalNameRecord extends StandardRecord { public String toString() { StringBuffer sb = new StringBuffer(); sb.append("[EXTERNALNAME]\n"); + sb.append(" .options = ").append(field_1_option_flag).append("\n"); sb.append(" .ix = ").append(field_2_ixals).append("\n"); sb.append(" .name = ").append(field_4_name).append("\n"); if(field_5_name_definition != null) { - sb.append(" .formula = ").append(field_5_name_definition).append("\n"); + Ptg[] ptgs = field_5_name_definition.getTokens(); + for (int i = 0; i < ptgs.length; i++) { + Ptg ptg = ptgs[i]; + sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n"); + } } sb.append("[/EXTERNALNAME]\n"); return sb.toString(); diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index 338df7c5d4..4445838857 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -359,7 +359,7 @@ public final class FormulaRecord extends CellRecord { sb.append(" .alwaysCalc= ").append(isAlwaysCalc()).append("\n"); sb.append(" .calcOnLoad= ").append(isCalcOnLoad()).append("\n"); sb.append(" .shared = ").append(isSharedFormula()).append("\n"); - sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)); + sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n"); Ptg[] ptgs = field_8_parsed_expr.getTokens(); for (int k = 0; k < ptgs.length; k++ ) { diff --git a/src/java/org/apache/poi/hssf/record/SupBookRecord.java b/src/java/org/apache/poi/hssf/record/SupBookRecord.java index c519b93daa..b8be5deab4 100644 --- a/src/java/org/apache/poi/hssf/record/SupBookRecord.java +++ b/src/java/org/apache/poi/hssf/record/SupBookRecord.java @@ -47,7 +47,7 @@ public final class SupBookRecord extends StandardRecord { return new SupBookRecord(false, numberOfSheets); } public static SupBookRecord createAddInFunctions() { - return new SupBookRecord(true, (short)0); + return new SupBookRecord(true, (short)1 /* this field MUST be 0x0001 for add-in referencing */); } public static SupBookRecord createExternalReferences(String url, String[] sheetNames) { return new SupBookRecord(url, sheetNames); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java index 86d2c7fe95..ac57ba7dac 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java @@ -33,6 +33,7 @@ import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.formula.FormulaParsingWorkbook; import org.apache.poi.ss.formula.FormulaRenderingWorkbook; import org.apache.poi.ss.formula.FormulaType; +import org.apache.poi.ss.formula.udf.UDFFinder; /** * Internal POI use only @@ -65,7 +66,9 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E } public NameXPtg getNameXPtg(String name) { - return _iBook.getNameXPtg(name); + // TODO YK: passing UDFFinder.DEFAULT is temporary, + // a proper design should take it from the parent HSSFWorkbook + return _iBook.getNameXPtg(name, UDFFinder.DEFAULT); } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index f255931d80..3504a6b051 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -1679,12 +1679,4 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss private static byte[] newUID() { return new byte[16]; } - - /** - * Note - This method should only used by POI internally. - * It may get deleted or change definition in future POI versions - */ - public NameXPtg getNameXPtg(String name) { - return workbook.getNameXPtg(name); - } } diff --git a/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java b/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java index 72097b2a61..f053ba14b6 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java +++ b/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java @@ -27,13 +27,12 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.NameCommentRecord; -import org.apache.poi.hssf.record.NameRecord; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.SSTRecord; -import org.apache.poi.hssf.record.SupBookRecord; +import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.usermodel.TestHSSFWorkbook; +import org.apache.poi.ss.formula.ptg.NameXPtg; + /** * Tests for {@link LinkTable} * @@ -179,4 +178,86 @@ public final class TestLinkTable extends TestCase { assertEquals(2, lt.getNumNames()); } + + public void testAddNameX(){ + WorkbookRecordList wrl = new WorkbookRecordList(); + wrl.add(0, new BOFRecord()); + wrl.add(1, new CountryRecord()); + wrl.add(2, EOFRecord.instance); + + int numberOfSheets = 3; + LinkTable tbl = new LinkTable(numberOfSheets, wrl); + // creation of a new LinkTable insert two new records: SupBookRecord followed by ExternSheetRecord + // assure they are in place: + // [BOFRecord] + // [CountryRecord] + // [SUPBOOK Internal References nSheets= 3] + // [EXTERNSHEET] + // [EOFRecord] + + assertEquals(5, wrl.getRecords().size()); + assertTrue(wrl.get(2) instanceof SupBookRecord); + SupBookRecord sup1 = (SupBookRecord)wrl.get(2); + assertEquals(numberOfSheets, sup1.getNumberOfSheets()); + assertTrue(wrl.get(3) instanceof ExternSheetRecord); + ExternSheetRecord extSheet = (ExternSheetRecord)wrl.get(3); + assertEquals(0, extSheet.getNumOfRefs()); + + assertNull(tbl.getNameXPtg("ISODD")); + assertEquals(5, wrl.getRecords().size()); //still have five records + + NameXPtg namex1 = tbl.addNameXPtg("ISODD"); // adds two new rercords + assertEquals(0, namex1.getSheetRefIndex()); + assertEquals(0, namex1.getNameIndex()); + assertEquals(namex1.toString(), tbl.getNameXPtg("ISODD").toString()); + // assure they are in place: + // [BOFRecord] + // [CountryRecord] + // [SUPBOOK Internal References nSheets= 3] + // [SUPBOOK Add-In Functions nSheets= 1] + // [EXTERNALNAME .name = ISODD] + // [EXTERNSHEET] + // [EOFRecord] + + assertEquals(7, wrl.getRecords().size()); + assertTrue(wrl.get(3) instanceof SupBookRecord); + SupBookRecord sup2 = (SupBookRecord)wrl.get(3); + assertTrue(sup2.isAddInFunctions()); + assertTrue(wrl.get(4) instanceof ExternalNameRecord); + ExternalNameRecord ext1 = (ExternalNameRecord)wrl.get(4); + assertEquals("ISODD", ext1.getText()); + assertTrue(wrl.get(5) instanceof ExternSheetRecord); + assertEquals(1, extSheet.getNumOfRefs()); + + //check that + assertEquals(0, tbl.resolveNameXIx(namex1.getSheetRefIndex(), namex1.getNameIndex())); + assertEquals("ISODD", tbl.resolveNameXText(namex1.getSheetRefIndex(), namex1.getNameIndex())); + + assertNull(tbl.getNameXPtg("ISEVEN")); + NameXPtg namex2 = tbl.addNameXPtg("ISEVEN"); // adds two new rercords + assertEquals(0, namex2.getSheetRefIndex()); + assertEquals(1, namex2.getNameIndex()); // name index increased by one + assertEquals(namex2.toString(), tbl.getNameXPtg("ISEVEN").toString()); + assertEquals(8, wrl.getRecords().size()); + // assure they are in place: + // [BOFRecord] + // [CountryRecord] + // [SUPBOOK Internal References nSheets= 3] + // [SUPBOOK Add-In Functions nSheets= 1] + // [EXTERNALNAME .name = ISODD] + // [EXTERNALNAME .name = ISEVEN] + // [EXTERNSHEET] + // [EOFRecord] + assertTrue(wrl.get(3) instanceof SupBookRecord); + assertTrue(wrl.get(4) instanceof ExternalNameRecord); + assertTrue(wrl.get(5) instanceof ExternalNameRecord); + assertEquals("ISODD", ((ExternalNameRecord)wrl.get(4)).getText()); + assertEquals("ISEVEN", ((ExternalNameRecord)wrl.get(5)).getText()); + assertTrue(wrl.get(6) instanceof ExternSheetRecord); + assertTrue(wrl.get(7) instanceof EOFRecord); + + assertEquals(0, tbl.resolveNameXIx(namex2.getSheetRefIndex(), namex2.getNameIndex())); + assertEquals("ISEVEN", tbl.resolveNameXText(namex2.getSheetRefIndex(), namex2.getNameIndex())); + + } } diff --git a/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java b/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java index d6f1e7c90b..8de2c77da8 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/model/TestWorkbook.java @@ -22,6 +22,13 @@ import junit.framework.TestCase; import org.apache.poi.hssf.record.FontRecord; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.TestHSSFWorkbook; +import org.apache.poi.ss.formula.udf.UDFFinder; +import org.apache.poi.ss.formula.udf.DefaultUDFFinder; +import org.apache.poi.ss.formula.udf.AggregatingUDFFinder; +import org.apache.poi.ss.formula.functions.FreeRefFunction; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NotImplementedException; +import org.apache.poi.ss.formula.OperationEvaluationContext; /** * Unit test for the Workbook class. @@ -83,4 +90,28 @@ public final class TestWorkbook extends TestCase { assertEquals(6, wb.getFontIndex(n7)); assertEquals(n7, wb.getFontRecordAt(6)); } + + public void testAddNameX(){ + InternalWorkbook wb = TestHSSFWorkbook.getInternalWorkbook(new HSSFWorkbook()); + assertNotNull(wb.getNameXPtg("ISODD", UDFFinder.DEFAULT)); + + FreeRefFunction NotImplemented = new FreeRefFunction() { + public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { + throw new RuntimeException("not implemented"); + } + }; + + /** + * register the two test UDFs in a UDF finder, to be passed to the evaluator + */ + UDFFinder udff1 = new DefaultUDFFinder(new String[] { "myFunc", }, + new FreeRefFunction[] { NotImplemented }); + UDFFinder udff2 = new DefaultUDFFinder(new String[] { "myFunc2", }, + new FreeRefFunction[] { NotImplemented }); + UDFFinder udff = new AggregatingUDFFinder(udff1, udff2); + assertNotNull(wb.getNameXPtg("myFunc", udff)); + assertNotNull(wb.getNameXPtg("myFunc2", udff)); + + assertNull(wb.getNameXPtg("myFunc3", udff)); // myFunc3 is unknown + } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java index 82ac62f70c..a01f0935b1 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java @@ -102,5 +102,12 @@ public final class TestSupBookRecord extends TestCase { SupBookRecord record = SupBookRecord.createExternalReferences(url, sheetNames); TestcaseRecordInputStream.confirmRecordEncoding(0x01AE, dataER, record.serialize()); - } + } + + public void testStoreAIF() { + SupBookRecord record = SupBookRecord.createAddInFunctions(); + assertEquals(1, record.getNumberOfSheets()); + assertTrue(record.isAddInFunctions()); + TestcaseRecordInputStream.confirmRecordEncoding(0x01AE, dataAIF, record.serialize()); + } }