/* * 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()); } } } } }