001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hssf.usermodel;
019:
020: import junit.framework.Assert;
021: import org.apache.poi.hssf.model.Sheet;
022: import org.apache.poi.hssf.model.Workbook;
023: import org.apache.poi.hssf.record.*;
024:
025: import java.util.List;
026:
027: /**
028: * Designed to check wither the records written actually make sense.
029: */
030: public class SanityChecker extends Assert {
031: static class CheckRecord {
032: Class record;
033: char occurance; // 1 = one time, M = 1..many times, * = 0..many, 0 = optional
034: private boolean together;
035:
036: public CheckRecord(Class record, char occurance) {
037: this (record, occurance, true);
038: }
039:
040: /**
041: * @param record The record type to check
042: * @param occurance The occurance 1 = occurs once, M = occurs many times
043: * @param together
044: */
045: public CheckRecord(Class record, char occurance,
046: boolean together) {
047: this .record = record;
048: this .occurance = occurance;
049: this .together = together;
050: }
051:
052: public Class getRecord() {
053: return record;
054: }
055:
056: public char getOccurance() {
057: return occurance;
058: }
059:
060: public boolean isRequired() {
061: return occurance == '1' || occurance == 'M';
062: }
063:
064: public boolean isOptional() {
065: return occurance == '0' || occurance == '*';
066: }
067:
068: public boolean isTogether() {
069: return together;
070: }
071:
072: public boolean isMany() {
073: return occurance == '*' || occurance == 'M';
074: }
075:
076: public int match(List records, int recordIdx) {
077: int firstRecord = findFirstRecord(records, getRecord(),
078: recordIdx);
079: if (isRequired()) {
080: return matchRequired(firstRecord, records, recordIdx);
081: } else {
082: return matchOptional(firstRecord, records, recordIdx);
083: }
084: }
085:
086: private int matchOptional(int firstRecord, List records,
087: int recordIdx) {
088: if (firstRecord == -1) {
089: return recordIdx;
090: }
091:
092: return matchOneOrMany(records, firstRecord);
093: // return matchOneOrMany( records, recordIdx );
094: }
095:
096: private int matchRequired(int firstRecord, List records,
097: int recordIdx) {
098: if (firstRecord == -1) {
099: fail("Manditory record missing or out of order: "
100: + record);
101: }
102:
103: return matchOneOrMany(records, firstRecord);
104: // return matchOneOrMany( records, recordIdx );
105: }
106:
107: private int matchOneOrMany(List records, int recordIdx) {
108: if (isZeroOrOne()) {
109: // check no other records
110: if (findFirstRecord(records, getRecord(), recordIdx + 1) != -1)
111: fail("More than one record matched for "
112: + getRecord().getName());
113: } else if (isZeroToMany()) {
114: if (together) {
115: int nextIdx = findFirstRecord(records, record,
116: recordIdx + 1);
117: while (nextIdx != -1) {
118: if (nextIdx - 1 != recordIdx)
119: fail("Records are not together "
120: + record.getName());
121: recordIdx = nextIdx;
122: nextIdx = findFirstRecord(records, record,
123: recordIdx + 1);
124: }
125: }
126: }
127: return recordIdx + 1;
128: }
129:
130: private boolean isZeroToMany() {
131: return occurance == '*' || occurance == 'M';
132: }
133:
134: private boolean isZeroOrOne() {
135: return occurance == '0' || occurance == '1';
136: }
137: }
138:
139: CheckRecord[] workbookRecords = new CheckRecord[] {
140: new CheckRecord(BOFRecord.class, '1'),
141: new CheckRecord(InterfaceHdrRecord.class, '1'),
142: new CheckRecord(MMSRecord.class, '1'),
143: new CheckRecord(InterfaceEndRecord.class, '1'),
144: new CheckRecord(WriteAccessRecord.class, '1'),
145: new CheckRecord(CodepageRecord.class, '1'),
146: new CheckRecord(DSFRecord.class, '1'),
147: new CheckRecord(TabIdRecord.class, '1'),
148: new CheckRecord(FnGroupCountRecord.class, '1'),
149: new CheckRecord(WindowProtectRecord.class, '1'),
150: new CheckRecord(ProtectRecord.class, '1'),
151: new CheckRecord(PasswordRev4Record.class, '1'),
152: new CheckRecord(WindowOneRecord.class, '1'),
153: new CheckRecord(BackupRecord.class, '1'),
154: new CheckRecord(HideObjRecord.class, '1'),
155: new CheckRecord(DateWindow1904Record.class, '1'),
156: new CheckRecord(PrecisionRecord.class, '1'),
157: new CheckRecord(RefreshAllRecord.class, '1'),
158: new CheckRecord(BookBoolRecord.class, '1'),
159: new CheckRecord(FontRecord.class, 'M'),
160: new CheckRecord(FormatRecord.class, 'M'),
161: new CheckRecord(ExtendedFormatRecord.class, 'M'),
162: new CheckRecord(StyleRecord.class, 'M'),
163: new CheckRecord(UseSelFSRecord.class, '1'),
164: new CheckRecord(BoundSheetRecord.class, 'M'),
165: new CheckRecord(CountryRecord.class, '1'),
166: new CheckRecord(SupBookRecord.class, '0'),
167: new CheckRecord(ExternSheetRecord.class, '0'),
168: new CheckRecord(NameRecord.class, '*'),
169: new CheckRecord(SSTRecord.class, '1'),
170: new CheckRecord(ExtSSTRecord.class, '1'),
171: new CheckRecord(EOFRecord.class, '1'), };
172:
173: CheckRecord[] sheetRecords = new CheckRecord[] {
174: new CheckRecord(BOFRecord.class, '1'),
175: new CheckRecord(CalcModeRecord.class, '1'),
176: new CheckRecord(RefModeRecord.class, '1'),
177: new CheckRecord(IterationRecord.class, '1'),
178: new CheckRecord(DeltaRecord.class, '1'),
179: new CheckRecord(SaveRecalcRecord.class, '1'),
180: new CheckRecord(PrintHeadersRecord.class, '1'),
181: new CheckRecord(PrintGridlinesRecord.class, '1'),
182: new CheckRecord(GridsetRecord.class, '1'),
183: new CheckRecord(GutsRecord.class, '1'),
184: new CheckRecord(DefaultRowHeightRecord.class, '1'),
185: new CheckRecord(WSBoolRecord.class, '1'),
186: new CheckRecord(HeaderRecord.class, '1'),
187: new CheckRecord(FooterRecord.class, '1'),
188: new CheckRecord(HCenterRecord.class, '1'),
189: new CheckRecord(VCenterRecord.class, '1'),
190: new CheckRecord(PrintSetupRecord.class, '1'),
191: new CheckRecord(DefaultColWidthRecord.class, '1'),
192: new CheckRecord(DimensionsRecord.class, '1'),
193: new CheckRecord(WindowTwoRecord.class, '1'),
194: new CheckRecord(SelectionRecord.class, '1'),
195: new CheckRecord(EOFRecord.class, '1') };
196:
197: private void checkWorkbookRecords(Workbook workbook) {
198: List records = workbook.getRecords();
199: assertTrue(records.get(0) instanceof BOFRecord);
200: assertTrue(records.get(records.size() - 1) instanceof EOFRecord);
201:
202: checkRecordOrder(records, workbookRecords);
203: // checkRecordsTogether(records, workbookRecords);
204: }
205:
206: private void checkSheetRecords(Sheet sheet) {
207: List records = sheet.getRecords();
208: assertTrue(records.get(0) instanceof BOFRecord);
209: assertTrue(records.get(records.size() - 1) instanceof EOFRecord);
210:
211: checkRecordOrder(records, sheetRecords);
212: // checkRecordsTogether(records, sheetRecords);
213: }
214:
215: public void checkHSSFWorkbook(HSSFWorkbook wb) {
216: checkWorkbookRecords(wb.getWorkbook());
217: for (int i = 0; i < wb.getNumberOfSheets(); i++)
218: checkSheetRecords(wb.getSheetAt(i).getSheet());
219:
220: }
221:
222: /*
223: private void checkRecordsTogether(List records, CheckRecord[] check)
224: {
225: for ( int checkIdx = 0; checkIdx < check.length; checkIdx++ )
226: {
227: int recordIdx = findFirstRecord(records, check[checkIdx].getRecord());
228: boolean notFoundAndRecordRequired = (recordIdx == -1 && check[checkIdx].isRequired());
229: if (notFoundAndRecordRequired)
230: {
231: fail("Expected to find record of class " + check.getClass() + " but did not");
232: }
233: else if (recordIdx >= 0)
234: {
235: if (check[checkIdx].isMany())
236: {
237: // Skip records that are together
238: while (recordIdx < records.size() && check[checkIdx].getRecord().isInstance(records.get(recordIdx)))
239: recordIdx++;
240: }
241:
242: // Make sure record does not occur in remaining records (after the next)
243: recordIdx++;
244: for (int recordIdx2 = recordIdx; recordIdx2 < records.size(); recordIdx2++)
245: {
246: if (check[checkIdx].getRecord().isInstance(records.get(recordIdx2)))
247: fail("Record occurs scattered throughout record chain:\n" + records.get(recordIdx2));
248: }
249: }
250: }
251: } */
252:
253: private static int findFirstRecord(List records, Class record,
254: int startIndex) {
255: for (int i = startIndex; i < records.size(); i++) {
256: if (record.getName().equals(
257: records.get(i).getClass().getName()))
258: return i;
259: }
260: return -1;
261: }
262:
263: // private static int findFirstRecord( List records, Class record )
264: // {
265: // return findFirstRecord ( records, record, 0 );
266: // }
267:
268: void checkRecordOrder(List records, CheckRecord[] check) {
269: int recordIdx = 0;
270: for (int checkIdx = 0; checkIdx < check.length; checkIdx++) {
271: recordIdx = check[checkIdx].match(records, recordIdx);
272: }
273: }
274:
275: /*
276: void checkRecordOrder(List records, CheckRecord[] check)
277: {
278: int checkIndex = 0;
279: for (int recordIndex = 0; recordIndex < records.size(); recordIndex++)
280: {
281: Record record = (Record) records.get(recordIndex);
282: if (check[checkIndex].getRecord().isInstance(record))
283: {
284: if (check[checkIndex].getOccurance() == 'M')
285: {
286: // skip over duplicate records if multiples are allowed
287: while (recordIndex+1 < records.size() && check[checkIndex].getRecord().isInstance(records.get(recordIndex+1)))
288: recordIndex++;
289: // lastGoodMatch = recordIndex;
290: }
291: else if (check[checkIndex].getOccurance() == '1')
292: {
293: // Check next record to make sure there's not more than one
294: if (recordIndex != records.size() - 1)
295: {
296: if (check[checkIndex].getRecord().isInstance(records.get(recordIndex+1)))
297: {
298: fail("More than one occurance of record found:\n" + records.get(recordIndex).toString());
299: }
300: }
301: // lastGoodMatch = recordIndex;
302: }
303: // else if (check[checkIndex].getOccurance() == '0')
304: // {
305: //
306: // }
307: checkIndex++;
308: }
309: if (checkIndex >= check.length)
310: return;
311: }
312: fail("Could not find required record: " + check[checkIndex]);
313: } */
314:
315: }
|