/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.common.lucene.store;
import org.apache.lucene.store.IndexInput;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import static org.hamcrest.Matchers.containsString;
public class ByteArrayIndexInputTests extends ESTestCase {
public void testRandomReads() throws IOException {
for (int i = 0; i < 100; i++) {
byte[] input = randomUnicodeOfLength(randomIntBetween(1, 1000)).getBytes(StandardCharsets.UTF_8);
ByteArrayIndexInput indexInput = new ByteArrayIndexInput("test", input);
assertEquals(input.length, indexInput.length());
assertEquals(0, indexInput.getFilePointer());
byte[] output = randomReadAndSlice(indexInput, input.length);
assertArrayEquals(input, output);
}
}
public void testRandomOverflow() throws IOException {
for (int i = 0; i < 100; i++) {
byte[] input = randomUnicodeOfLength(randomIntBetween(1, 1000)).getBytes(StandardCharsets.UTF_8);
ByteArrayIndexInput indexInput = new ByteArrayIndexInput("test", input);
int firstReadLen = randomIntBetween(0, input.length - 1);
randomReadAndSlice(indexInput, firstReadLen);
int bytesLeft = input.length - firstReadLen;
try {
// read using int size
int secondReadLen = bytesLeft + randomIntBetween(1, 100);
indexInput.readBytes(new byte[secondReadLen], 0, secondReadLen);
fail();
} catch (IOException ex) {
assertThat(ex.getMessage(), containsString("EOF"));
}
}
}
public void testSeekOverflow() throws IOException {
for (int i = 0; i < 100; i++) {
byte[] input = randomUnicodeOfLength(randomIntBetween(1, 1000)).getBytes(StandardCharsets.UTF_8);
ByteArrayIndexInput indexInput = new ByteArrayIndexInput("test", input);
int firstReadLen = randomIntBetween(0, input.length - 1);
randomReadAndSlice(indexInput, firstReadLen);
try {
switch (randomIntBetween(0, 2)) {
case 0:
indexInput.seek(Integer.MAX_VALUE + 4L);
break;
case 1:
indexInput.seek(-randomIntBetween(1, 10));
break;
case 2:
int seek = input.length + randomIntBetween(1, 100);
indexInput.seek(seek);
break;
default:
fail();
}
fail();
} catch (IOException ex) {
assertThat(ex.getMessage(), containsString("EOF"));
} catch (IllegalArgumentException ex) {
assertThat(ex.getMessage(), containsString("negative position"));
}
}
}
private byte[] randomReadAndSlice(IndexInput indexInput, int length) throws IOException {
int readPos = (int) indexInput.getFilePointer();
byte[] output = new byte[length];
while (readPos < length) {
switch (randomIntBetween(0, 3)) {
case 0:
// Read by one byte at a time
output[readPos++] = indexInput.readByte();
break;
case 1:
// Read several bytes into target
int len = randomIntBetween(1, length - readPos);
indexInput.readBytes(output, readPos, len);
readPos += len;
break;
case 2:
// Read several bytes into 0-offset target
len = randomIntBetween(1, length - readPos);
byte[] temp = new byte[len];
indexInput.readBytes(temp, 0, len);
System.arraycopy(temp, 0, output, readPos, len);
readPos += len;
break;
case 3:
// Read using slice
len = randomIntBetween(1, length - readPos);
IndexInput slice = indexInput.slice("slice (" + readPos + ", " + len + ") of " + indexInput.toString(), readPos, len);
temp = randomReadAndSlice(slice, len);
// assert that position in the original input didn't change
assertEquals(readPos, indexInput.getFilePointer());
System.arraycopy(temp, 0, output, readPos, len);
readPos += len;
indexInput.seek(readPos);
assertEquals(readPos, indexInput.getFilePointer());
break;
default:
fail();
}
assertEquals(readPos, indexInput.getFilePointer());
}
return output;
}
}