FileUtilArrayReadTest.java

/*******************************************************************************
 * Copyright (c) 2026 Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package org.aspectj.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import junit.framework.TestCase;

/**
 * Checks that the array readers reject an invalid length prefix before allocating anything.
 */
public class FileUtilArrayReadTest extends TestCase {

	private interface ArrayReader {
		void read(DataInputStream s) throws IOException;
	}

	/** A length prefix followed by the given number of zero bytes, enough for that many elements of any kind. */
	private static DataInputStream streamStartingWithLength(int length, int bytesOfData) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		new DataOutputStream(bos).writeInt(length);
		bos.write(new byte[bytesOfData]);
		return new DataInputStream(new ByteArrayInputStream(bos.toByteArray()));
	}

	private static void assertRejected(ArrayReader reader, int length, int bytesOfData) throws IOException {
		try {
			reader.read(streamStartingWithLength(length, bytesOfData));
			fail("expected length " + length + " to be rejected");
		} catch (IOException expected) {
		}
	}

	private static void assertAllRejected(int length, int bytesOfData) throws IOException {
		assertRejected(FileUtil::readBooleanArray, length, bytesOfData);
		assertRejected(FileUtil::readIntArray, length, bytesOfData);
		assertRejected(FileUtil::readStringArray, length, bytesOfData);
	}

	public void testHugeLengthIsRejected() throws IOException {
		assertAllRejected(Integer.MAX_VALUE, 0);
	}

	public void testNegativeLengthIsRejected() throws IOException {
		assertAllRejected(-1, 0);
	}

	public void testLengthJustOverTheLimitIsRejectedEvenWhenTheDataIsPresent() throws IOException {
		assertAllRejected(0x10000, 4 * 0x10000);
	}

	public void testValidArraysStillRead() throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		DataOutputStream out = new DataOutputStream(bos);
		FileUtil.writeBooleanArray(new boolean[] { true, false }, out);
		FileUtil.writeIntArray(new int[] { 1, 2, 3 }, out);
		FileUtil.writeStringArray(new String[] { "a", "b" }, out);
		FileUtil.writeBooleanArray(new boolean[0], out);
		FileUtil.writeIntArray(new int[0], out);
		FileUtil.writeStringArray(new String[0], out);

		DataInputStream in = new DataInputStream(new ByteArrayInputStream(bos.toByteArray()));
		assertEquals(2, FileUtil.readBooleanArray(in).length);
		assertEquals(3, FileUtil.readIntArray(in).length);
		assertEquals(2, FileUtil.readStringArray(in).length);
		assertEquals(0, FileUtil.readBooleanArray(in).length);
		assertEquals(0, FileUtil.readIntArray(in).length);
		assertEquals(0, FileUtil.readStringArray(in).length);
	}
}