blob: ce5a52ba6ddb3966984794afb1b44a875ab5ab1a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.util.fst;
import java.util.Arrays;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
public class TestBytesStore extends LuceneTestCase {
public void testRandom() throws Exception {
final int iters = atLeast(10);
final int maxBytes = TEST_NIGHTLY ? 200000 : 20000;
for(int iter=0;iter<iters;iter++) {
final int numBytes = TestUtil.nextInt(random(), 1, maxBytes);
final byte[] expected = new byte[numBytes];
final int blockBits = TestUtil.nextInt(random(), 8, 15);
final BytesStore bytes = new BytesStore(blockBits);
if (VERBOSE) {
System.out.println("TEST: iter=" + iter + " numBytes=" + numBytes + " blockBits=" + blockBits);
}
int pos = 0;
while(pos < numBytes) {
int op = random().nextInt(8);
if (VERBOSE) {
System.out.println(" cycle pos=" + pos);
}
switch(op) {
case 0:
{
// write random byte
byte b = (byte) random().nextInt(256);
if (VERBOSE) {
System.out.println(" writeByte b=" + b);
}
expected[pos++] = b;
bytes.writeByte(b);
}
break;
case 1:
{
// write random byte[]
int len = random().nextInt(Math.min(numBytes - pos, 100));
byte[] temp = new byte[len];
random().nextBytes(temp);
if (VERBOSE) {
System.out.println(" writeBytes len=" + len + " bytes=" + Arrays.toString(temp));
}
System.arraycopy(temp, 0, expected, pos, temp.length);
bytes.writeBytes(temp, 0, temp.length);
pos += len;
}
break;
case 2:
{
// write int @ absolute pos
if (pos > 4) {
int x = random().nextInt();
int randomPos = random().nextInt(pos-4);
if (VERBOSE) {
System.out.println(" abs writeInt pos=" + randomPos + " x=" + x);
}
bytes.writeInt(randomPos, x);
expected[randomPos++] = (byte) (x >> 24);
expected[randomPos++] = (byte) (x >> 16);
expected[randomPos++] = (byte) (x >> 8);
expected[randomPos++] = (byte) x;
}
}
break;
case 3:
{
// reverse bytes
if (pos > 1) {
int len = TestUtil.nextInt(random(), 2, Math.min(100, pos));
int start;
if (len == pos) {
start = 0;
} else {
start = random().nextInt(pos - len);
}
int end = start + len - 1;
if (VERBOSE) {
System.out.println(" reverse start=" + start + " end=" + end + " len=" + len + " pos=" + pos);
}
bytes.reverse(start, end);
while(start <= end) {
byte b = expected[end];
expected[end] = expected[start];
expected[start] = b;
start++;
end--;
}
}
}
break;
case 4:
{
// abs write random byte[]
if (pos > 2) {
int randomPos = random().nextInt(pos-1);
int len = TestUtil.nextInt(random(), 1, Math.min(pos - randomPos - 1, 100));
byte[] temp = new byte[len];
random().nextBytes(temp);
if (VERBOSE) {
System.out.println(" abs writeBytes pos=" + randomPos + " len=" + len + " bytes=" + Arrays.toString(temp));
}
System.arraycopy(temp, 0, expected, randomPos, temp.length);
bytes.writeBytes(randomPos, temp, 0, temp.length);
}
}
break;
case 5:
{
// copyBytes
if (pos > 1) {
int src = random().nextInt(pos-1);
int dest = TestUtil.nextInt(random(), src + 1, pos - 1);
int len = TestUtil.nextInt(random(), 1, Math.min(300, pos - dest));
if (VERBOSE) {
System.out.println(" copyBytes src=" + src + " dest=" + dest + " len=" + len);
}
System.arraycopy(expected, src, expected, dest, len);
bytes.copyBytes(src, dest, len);
}
}
break;
case 6:
{
// skip
int len = random().nextInt(Math.min(100, numBytes - pos));
if (VERBOSE) {
System.out.println(" skip len=" + len);
}
pos += len;
bytes.skipBytes(len);
// NOTE: must fill in zeros in case truncate was
// used, else we get false fails:
if (len > 0) {
byte[] zeros = new byte[len];
bytes.writeBytes(pos-len, zeros, 0, len);
}
}
break;
case 7:
{
// absWriteByte
if (pos > 0) {
int dest = random().nextInt(pos);
byte b = (byte) random().nextInt(256);
expected[dest] = b;
bytes.writeByte(dest, b);
}
break;
}
}
assertEquals(pos, bytes.getPosition());
if (pos > 0 && random().nextInt(50) == 17) {
// truncate
int len = TestUtil.nextInt(random(), 1, Math.min(pos, 100));
bytes.truncate(pos - len);
pos -= len;
Arrays.fill(expected, pos, pos+len, (byte) 0);
if (VERBOSE) {
System.out.println(" truncate len=" + len + " newPos=" + pos);
}
}
if ((pos > 0 && random().nextInt(200) == 17)) {
verify(bytes, expected, pos);
}
}
BytesStore bytesToVerify;
if (random().nextBoolean()) {
if (VERBOSE) {
System.out.println("TEST: save/load final bytes");
}
Directory dir = newDirectory();
IndexOutput out = dir.createOutput("bytes", IOContext.DEFAULT);
bytes.writeTo(out);
out.close();
IndexInput in = dir.openInput("bytes", IOContext.DEFAULT);
bytesToVerify = new BytesStore(in, numBytes, TestUtil.nextInt(random(), 256, Integer.MAX_VALUE));
in.close();
dir.close();
} else {
bytesToVerify = bytes;
}
verify(bytesToVerify, expected, numBytes);
}
}
private void verify(BytesStore bytes, byte[] expected, int totalLength) throws Exception {
assertEquals(totalLength, bytes.getPosition());
if (totalLength == 0) {
return;
}
if (VERBOSE) {
System.out.println(" verify...");
}
// First verify whole thing in one blast:
byte[] actual = new byte[totalLength];
if (random().nextBoolean()) {
if (VERBOSE) {
System.out.println(" bulk: reversed");
}
// reversed
FST.BytesReader r = bytes.getReverseReader();
assertTrue(r.reversed());
r.setPosition(totalLength-1);
r.readBytes(actual, 0, actual.length);
int start = 0;
int end = totalLength - 1;
while(start < end) {
byte b = actual[start];
actual[start] = actual[end];
actual[end] = b;
start++;
end--;
}
} else {
// forward
if (VERBOSE) {
System.out.println(" bulk: forward");
}
FST.BytesReader r = bytes.getForwardReader();
assertFalse(r.reversed());
r.readBytes(actual, 0, actual.length);
}
for(int i=0;i<totalLength;i++) {
assertEquals("byte @ index=" + i, expected[i], actual[i]);
}
FST.BytesReader r;
// Then verify ops:
boolean reversed = random().nextBoolean();
if (reversed) {
if (VERBOSE) {
System.out.println(" ops: reversed");
}
r = bytes.getReverseReader();
} else {
if (VERBOSE) {
System.out.println(" ops: forward");
}
r = bytes.getForwardReader();
}
if (totalLength > 1) {
int numOps = TestUtil.nextInt(random(), 100, 200);
for(int op=0;op<numOps;op++) {
int numBytes = random().nextInt(Math.min(1000, totalLength-1));
int pos;
if (reversed) {
pos = TestUtil.nextInt(random(), numBytes, totalLength - 1);
} else {
pos = random().nextInt(totalLength-numBytes);
}
if (VERBOSE) {
System.out.println(" op iter=" + op + " reversed=" + reversed + " numBytes=" + numBytes + " pos=" + pos);
}
byte[] temp = new byte[numBytes];
r.setPosition(pos);
assertEquals(pos, r.getPosition());
r.readBytes(temp, 0, temp.length);
for(int i=0;i<numBytes;i++) {
byte expectedByte;
if (reversed) {
expectedByte = expected[pos - i];
} else {
expectedByte = expected[pos + i];
}
assertEquals("byte @ index=" + i, expectedByte, temp[i]);
}
int left;
int expectedPos;
if (reversed) {
expectedPos = pos-numBytes;
left = (int) r.getPosition();
} else {
expectedPos = pos+numBytes;
left = (int) (totalLength - r.getPosition());
}
assertEquals(expectedPos, r.getPosition());
if (left > 4) {
int skipBytes = random().nextInt(left-4);
int expectedInt = 0;
if (reversed) {
expectedPos -= skipBytes;
expectedInt |= (expected[expectedPos--]&0xFF)<<24;
expectedInt |= (expected[expectedPos--]&0xFF)<<16;
expectedInt |= (expected[expectedPos--]&0xFF)<<8;
expectedInt |= (expected[expectedPos--]&0xFF);
} else {
expectedPos += skipBytes;
expectedInt |= (expected[expectedPos++]&0xFF)<<24;
expectedInt |= (expected[expectedPos++]&0xFF)<<16;
expectedInt |= (expected[expectedPos++]&0xFF)<<8;
expectedInt |= (expected[expectedPos++]&0xFF);
}
if (VERBOSE) {
System.out.println(" skip numBytes=" + skipBytes);
System.out.println(" readInt");
}
r.skipBytes(skipBytes);
assertEquals(expectedInt, r.readInt());
}
}
}
}
}