mirror of https://github.com/apache/poi.git
Apply patch for bug 57151: Document CellRangeAddress and add some validation to prevent invalid row/column combinations.
Cover class CellRangeAddress fully in unit tests. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1635389 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3b341743de
commit
c3753981dd
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.util;
|
package org.apache.poi.ss.util;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.SheetNameFormatter;
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.record.SelectionRecord;
|
import org.apache.poi.hssf.record.SelectionRecord;
|
||||||
|
import org.apache.poi.ss.formula.SheetNameFormatter;
|
||||||
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
|
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
|
@ -38,14 +38,26 @@ public class CellRangeAddress extends CellRangeAddressBase {
|
||||||
*/
|
*/
|
||||||
public static final int ENCODED_SIZE = 8;
|
public static final int ENCODED_SIZE = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new cell range. Indexes are zero-based.
|
||||||
|
*
|
||||||
|
* @param firstRow Index of first row
|
||||||
|
* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow}
|
||||||
|
* @param firstCol Index of first column
|
||||||
|
* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol}
|
||||||
|
*/
|
||||||
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
|
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
|
||||||
super(firstRow, lastRow, firstCol, lastCol);
|
super(firstRow, lastRow, firstCol, lastCol);
|
||||||
|
|
||||||
|
if (lastRow < firstRow || lastCol < firstCol)
|
||||||
|
throw new IllegalArgumentException("lastRow < firstRow || lastCol < firstCol");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use {@link #serialize(LittleEndianOutput)}
|
* @deprecated use {@link #serialize(LittleEndianOutput)}
|
||||||
*/
|
*/
|
||||||
public int serialize(int offset, byte[] data) {
|
@Deprecated
|
||||||
|
public int serialize(int offset, byte[] data) {
|
||||||
serialize(new LittleEndianByteArrayOutputStream(data, offset, ENCODED_SIZE));
|
serialize(new LittleEndianByteArrayOutputStream(data, offset, ENCODED_SIZE));
|
||||||
return ENCODED_SIZE;
|
return ENCODED_SIZE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
|
||||||
super(out);
|
super(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeByte(int v) {
|
@Override
|
||||||
|
public void writeByte(int v) {
|
||||||
try {
|
try {
|
||||||
out.write(v);
|
out.write(v);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -38,11 +39,13 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeDouble(double v) {
|
@Override
|
||||||
|
public void writeDouble(double v) {
|
||||||
writeLong(Double.doubleToLongBits(v));
|
writeLong(Double.doubleToLongBits(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeInt(int v) {
|
@Override
|
||||||
|
public void writeInt(int v) {
|
||||||
int b3 = (v >>> 24) & 0xFF;
|
int b3 = (v >>> 24) & 0xFF;
|
||||||
int b2 = (v >>> 16) & 0xFF;
|
int b2 = (v >>> 16) & 0xFF;
|
||||||
int b1 = (v >>> 8) & 0xFF;
|
int b1 = (v >>> 8) & 0xFF;
|
||||||
|
@ -57,12 +60,14 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeLong(long v) {
|
@Override
|
||||||
|
public void writeLong(long v) {
|
||||||
writeInt((int)(v >> 0));
|
writeInt((int)(v >> 0));
|
||||||
writeInt((int)(v >> 32));
|
writeInt((int)(v >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeShort(int v) {
|
@Override
|
||||||
|
public void writeShort(int v) {
|
||||||
int b1 = (v >>> 8) & 0xFF;
|
int b1 = (v >>> 8) & 0xFF;
|
||||||
int b0 = (v >>> 0) & 0xFF;
|
int b0 = (v >>> 0) & 0xFF;
|
||||||
try {
|
try {
|
||||||
|
@ -72,7 +77,8 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void write(byte[] b) {
|
@Override
|
||||||
|
public void write(byte[] b) {
|
||||||
// suppress IOException for interface method
|
// suppress IOException for interface method
|
||||||
try {
|
try {
|
||||||
super.write(b);
|
super.write(b);
|
||||||
|
@ -80,7 +86,8 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void write(byte[] b, int off, int len) {
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) {
|
||||||
// suppress IOException for interface method
|
// suppress IOException for interface method
|
||||||
try {
|
try {
|
||||||
super.write(b, off, len);
|
super.write(b, off, len);
|
||||||
|
|
|
@ -18,63 +18,176 @@ limitations under the License.
|
||||||
package org.apache.poi.ss.util;
|
package org.apache.poi.ss.util;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
|
||||||
import org.apache.poi.util.LittleEndianOutputStream;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
||||||
|
import org.apache.poi.util.LittleEndianOutputStream;
|
||||||
|
|
||||||
public final class TestCellRangeAddress extends TestCase {
|
public final class TestCellRangeAddress extends TestCase {
|
||||||
byte[] data = new byte[] {
|
byte[] data = new byte[] { (byte) 0x02, (byte) 0x00, (byte) 0x04,
|
||||||
(byte)0x02,(byte)0x00,
|
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, };
|
||||||
(byte)0x04,(byte)0x00,
|
|
||||||
(byte)0x00,(byte)0x00,
|
|
||||||
(byte)0x03,(byte)0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
public void testLoad() {
|
public void testLoad() {
|
||||||
CellRangeAddress ref = new CellRangeAddress(
|
CellRangeAddress ref = new CellRangeAddress(
|
||||||
TestcaseRecordInputStream.create(0x000, data)
|
TestcaseRecordInputStream.create(0x000, data));
|
||||||
);
|
assertEquals(2, ref.getFirstRow());
|
||||||
assertEquals(2, ref.getFirstRow());
|
assertEquals(4, ref.getLastRow());
|
||||||
assertEquals(4, ref.getLastRow());
|
assertEquals(0, ref.getFirstColumn());
|
||||||
assertEquals(0, ref.getFirstColumn());
|
assertEquals(3, ref.getLastColumn());
|
||||||
assertEquals(3, ref.getLastColumn());
|
|
||||||
|
|
||||||
assertEquals( 8, CellRangeAddress.ENCODED_SIZE );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testStore()
|
assertEquals(8, CellRangeAddress.ENCODED_SIZE);
|
||||||
{
|
|
||||||
CellRangeAddress ref = new CellRangeAddress(0,0,0,0);
|
|
||||||
|
|
||||||
byte[] recordBytes;
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
LittleEndianOutputStream out = new LittleEndianOutputStream(baos);
|
|
||||||
|
|
||||||
// With nothing set
|
|
||||||
ref.serialize(out);
|
|
||||||
recordBytes = baos.toByteArray();
|
|
||||||
assertEquals(recordBytes.length, data.length);
|
|
||||||
for (int i = 0; i < data.length; i++) {
|
|
||||||
assertEquals("At offset " + i, 0, recordBytes[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now set the flags
|
public void testLoadInvalid() {
|
||||||
ref.setFirstRow((short)2);
|
try {
|
||||||
ref.setLastRow((short)4);
|
assertNotNull(new CellRangeAddress(
|
||||||
ref.setFirstColumn((short)0);
|
TestcaseRecordInputStream.create(0x000, new byte[] { (byte)0x02 })));
|
||||||
ref.setLastColumn((short)3);
|
} catch (RuntimeException e) {
|
||||||
|
assertTrue("Had: " + e, e.getMessage().contains("Ran out of data"));
|
||||||
// Re-test
|
}
|
||||||
baos.reset();
|
}
|
||||||
ref.serialize(out);
|
|
||||||
recordBytes = baos.toByteArray();
|
public void testStore() throws IOException {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(0, 0, 0, 0);
|
||||||
assertEquals(recordBytes.length, data.length);
|
|
||||||
for (int i = 0; i < data.length; i++) {
|
byte[] recordBytes;
|
||||||
assertEquals("At offset " + i, data[i], recordBytes[i]);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
LittleEndianOutputStream out = new LittleEndianOutputStream(baos);
|
||||||
|
try {
|
||||||
|
// With nothing set
|
||||||
|
ref.serialize(out);
|
||||||
|
recordBytes = baos.toByteArray();
|
||||||
|
assertEquals(recordBytes.length, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
assertEquals("At offset " + i, 0, recordBytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now set the flags
|
||||||
|
ref.setFirstRow((short) 2);
|
||||||
|
ref.setLastRow((short) 4);
|
||||||
|
ref.setFirstColumn((short) 0);
|
||||||
|
ref.setLastColumn((short) 3);
|
||||||
|
|
||||||
|
// Re-test
|
||||||
|
baos.reset();
|
||||||
|
ref.serialize(out);
|
||||||
|
recordBytes = baos.toByteArray();
|
||||||
|
|
||||||
|
assertEquals(recordBytes.length, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
assertEquals("At offset " + i, data[i], recordBytes[i]);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void testStoreDeprecated() throws IOException {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(0, 0, 0, 0);
|
||||||
|
|
||||||
|
byte[] recordBytes = new byte[CellRangeAddress.ENCODED_SIZE];
|
||||||
|
// With nothing set
|
||||||
|
ref.serialize(0, recordBytes);
|
||||||
|
assertEquals(recordBytes.length, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
assertEquals("At offset " + i, 0, recordBytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now set the flags
|
||||||
|
ref.setFirstRow((short) 2);
|
||||||
|
ref.setLastRow((short) 4);
|
||||||
|
ref.setFirstColumn((short) 0);
|
||||||
|
ref.setLastColumn((short) 3);
|
||||||
|
|
||||||
|
// Re-test
|
||||||
|
ref.serialize(0, recordBytes);
|
||||||
|
|
||||||
|
assertEquals(recordBytes.length, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
assertEquals("At offset " + i, data[i], recordBytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateIllegal() throws IOException {
|
||||||
|
// for some combinations we expected exceptions
|
||||||
|
try {
|
||||||
|
assertNotNull(new CellRangeAddress(1, 0, 0, 0));
|
||||||
|
fail("Expect to catch an exception");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
assertNotNull(new CellRangeAddress(0, 0, 1, 0));
|
||||||
|
fail("Expect to catch an exception");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCopy() throws IOException {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(1, 2, 3, 4);
|
||||||
|
CellRangeAddress copy = ref.copy();
|
||||||
|
assertEquals(ref.toString(), copy.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetEncodedSize() throws IOException {
|
||||||
|
assertEquals(2*CellRangeAddress.ENCODED_SIZE, CellRangeAddress.getEncodedSize(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFormatAsString() throws IOException {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(1, 2, 3, 4);
|
||||||
|
|
||||||
|
assertEquals("D2:E3", ref.formatAsString());
|
||||||
|
assertEquals("D2:E3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString());
|
||||||
|
|
||||||
|
assertEquals("sheet1!$D$2:$E$3", ref.formatAsString("sheet1", true));
|
||||||
|
assertEquals("sheet1!$D$2:$E$3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", true));
|
||||||
|
assertEquals("sheet1!$D$2:$E$3", CellRangeAddress.valueOf(ref.formatAsString("sheet1", true)).formatAsString("sheet1", true));
|
||||||
|
|
||||||
|
assertEquals("sheet1!D2:E3", ref.formatAsString("sheet1", false));
|
||||||
|
assertEquals("sheet1!D2:E3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", false));
|
||||||
|
assertEquals("sheet1!D2:E3", CellRangeAddress.valueOf(ref.formatAsString("sheet1", false)).formatAsString("sheet1", false));
|
||||||
|
|
||||||
|
assertEquals("D2:E3", ref.formatAsString(null, false));
|
||||||
|
assertEquals("D2:E3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString(null, false));
|
||||||
|
assertEquals("D2:E3", CellRangeAddress.valueOf(ref.formatAsString(null, false)).formatAsString(null, false));
|
||||||
|
|
||||||
|
assertEquals("$D$2:$E$3", ref.formatAsString(null, true));
|
||||||
|
assertEquals("$D$2:$E$3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString(null, true));
|
||||||
|
assertEquals("$D$2:$E$3", CellRangeAddress.valueOf(ref.formatAsString(null, true)).formatAsString(null, true));
|
||||||
|
|
||||||
|
ref = new CellRangeAddress(-1, -1, 3, 4);
|
||||||
|
assertEquals("D:E", ref.formatAsString());
|
||||||
|
assertEquals("sheet1!$D:$E", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", true));
|
||||||
|
assertEquals("sheet1!$D:$E", CellRangeAddress.valueOf(ref.formatAsString("sheet1", true)).formatAsString("sheet1", true));
|
||||||
|
assertEquals("$D:$E", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString(null, true));
|
||||||
|
assertEquals("$D:$E", CellRangeAddress.valueOf(ref.formatAsString(null, true)).formatAsString(null, true));
|
||||||
|
assertEquals("sheet1!D:E", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", false));
|
||||||
|
assertEquals("sheet1!D:E", CellRangeAddress.valueOf(ref.formatAsString("sheet1", false)).formatAsString("sheet1", false));
|
||||||
|
|
||||||
|
ref = new CellRangeAddress(1, 2, -1, -1);
|
||||||
|
assertEquals("2:3", ref.formatAsString());
|
||||||
|
assertEquals("sheet1!$2:$3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", true));
|
||||||
|
assertEquals("sheet1!$2:$3", CellRangeAddress.valueOf(ref.formatAsString("sheet1", true)).formatAsString("sheet1", true));
|
||||||
|
assertEquals("$2:$3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString(null, true));
|
||||||
|
assertEquals("$2:$3", CellRangeAddress.valueOf(ref.formatAsString(null, true)).formatAsString(null, true));
|
||||||
|
assertEquals("sheet1!2:3", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", false));
|
||||||
|
assertEquals("sheet1!2:3", CellRangeAddress.valueOf(ref.formatAsString("sheet1", false)).formatAsString("sheet1", false));
|
||||||
|
|
||||||
|
ref = new CellRangeAddress(1, 1, 2, 2);
|
||||||
|
assertEquals("C2", ref.formatAsString());
|
||||||
|
assertEquals("sheet1!$C$2", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", true));
|
||||||
|
assertEquals("sheet1!$C$2", CellRangeAddress.valueOf(ref.formatAsString("sheet1", true)).formatAsString("sheet1", true));
|
||||||
|
assertEquals("$C$2", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString(null, true));
|
||||||
|
assertEquals("$C$2", CellRangeAddress.valueOf(ref.formatAsString(null, true)).formatAsString(null, true));
|
||||||
|
assertEquals("sheet1!C2", CellRangeAddress.valueOf(ref.formatAsString()).formatAsString("sheet1", false));
|
||||||
|
assertEquals("sheet1!C2", CellRangeAddress.valueOf(ref.formatAsString("sheet1", false)).formatAsString("sheet1", false));
|
||||||
|
|
||||||
|
// is this a valid address?
|
||||||
|
ref = new CellRangeAddress(-1, -1, -1, -1);
|
||||||
|
assertEquals(":", ref.formatAsString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue