/*
 * Copyright (C) 2009, Google Inc. and others
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0 which is available at
 * https://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.eclipse.jgit.util.io;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

import org.junit.Test;

public class UnionInputStreamTest {
	@Test
	public void testEmptyStream() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			assertTrue(u.isEmpty());
			assertEquals(-1, u.read());
			assertEquals(-1, u.read(new byte[1], 0, 1));
			assertEquals(0, u.available());
			assertEquals(0, u.skip(1));
		}
	}

	@Test
	public void testReadSingleBytes() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			assertTrue(u.isEmpty());
			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
			u.add(new ByteArrayInputStream(new byte[] { 3 }));
			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));

			assertFalse(u.isEmpty());
			assertEquals(3, u.available());
			assertEquals(1, u.read());
			assertEquals(0, u.read());
			assertEquals(2, u.read());
			assertEquals(0, u.available());

			assertEquals(3, u.read());
			assertEquals(0, u.available());

			assertEquals(4, u.read());
			assertEquals(1, u.available());
			assertEquals(5, u.read());
			assertEquals(0, u.available());
			assertEquals(-1, u.read());

			assertTrue(u.isEmpty());
			u.add(new ByteArrayInputStream(new byte[] { (byte) 255 }));
			assertEquals(255, u.read());
			assertEquals(-1, u.read());
			assertTrue(u.isEmpty());
		}
	}

	@Test
	public void testReadByteBlocks() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
			u.add(new ByteArrayInputStream(new byte[] { 3 }));
			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));

			final byte[] r = new byte[5];
			assertEquals(3, u.read(r, 0, 5));
			assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
			assertEquals(1, u.read(r, 0, 5));
			assertEquals(3, r[0]);
			assertEquals(2, u.read(r, 0, 5));
			assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
			assertEquals(-1, u.read(r, 0, 5));
		}
	}

	private static byte[] slice(byte[] in, int len) {
		byte[] r = new byte[len];
		System.arraycopy(in, 0, r, 0, len);
		return r;
	}

	@Test
	public void testArrayConstructor() throws IOException {
		try (UnionInputStream u = new UnionInputStream(
				new ByteArrayInputStream(new byte[] { 1, 0, 2 }),
				new ByteArrayInputStream(new byte[] { 3 }),
				new ByteArrayInputStream(new byte[] { 4, 5 }))) {
			final byte[] r = new byte[5];
			assertEquals(3, u.read(r, 0, 5));
			assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3)));
			assertEquals(1, u.read(r, 0, 5));
			assertEquals(3, r[0]);
			assertEquals(2, u.read(r, 0, 5));
			assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2)));
			assertEquals(-1, u.read(r, 0, 5));
		}
	}

	@Test
	public void testMarkSupported() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			assertFalse(u.markSupported());
			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
			assertFalse(u.markSupported());
		}
	}

	@Test
	public void testSkip() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 }));
			u.add(new ByteArrayInputStream(new byte[] { 3 }));
			u.add(new ByteArrayInputStream(new byte[] { 4, 5 }));
			assertEquals(0, u.skip(0));
			assertEquals(3, u.skip(3));
			assertEquals(3, u.read());
			assertEquals(2, u.skip(5));
			assertEquals(0, u.skip(5));
			assertEquals(-1, u.read());

			u.add(new ByteArrayInputStream(new byte[] { 20, 30 }) {
				@Override
				@SuppressWarnings("UnsynchronizedOverridesSynchronized")
				// This is only used in tests and is thread-safe
				public long skip(long n) {
					return 0;
				}
			});
			assertEquals(2, u.skip(8));
			assertEquals(-1, u.read());
		}
	}

	@Test
	public void testAutoCloseDuringRead() throws IOException {
		try (UnionInputStream u = new UnionInputStream()) {
			final boolean closed[] = new boolean[2];
			u.add(new ByteArrayInputStream(new byte[] { 1 }) {
				@Override
				public void close() {
					closed[0] = true;
				}
			});
			u.add(new ByteArrayInputStream(new byte[] { 2 }) {
				@Override
				public void close() {
					closed[1] = true;
				}
			});

			assertFalse(closed[0]);
			assertFalse(closed[1]);

			assertEquals(1, u.read());
			assertFalse(closed[0]);
			assertFalse(closed[1]);

			assertEquals(2, u.read());
			assertTrue(closed[0]);
			assertFalse(closed[1]);

			assertEquals(-1, u.read());
			assertTrue(closed[0]);
			assertTrue(closed[1]);
		}
	}

	@Test
	public void testCloseDuringClose() throws IOException {
		final boolean closed[] = new boolean[2];
		try (UnionInputStream u = new UnionInputStream()) {
			u.add(new ByteArrayInputStream(new byte[] { 1 }) {
				@Override
				public void close() {
					closed[0] = true;
				}
			});
			u.add(new ByteArrayInputStream(new byte[] { 2 }) {
				@Override
				public void close() {
					closed[1] = true;
				}
			});

			assertFalse(closed[0]);
			assertFalse(closed[1]);
		}

		assertTrue(closed[0]);
		assertTrue(closed[1]);
	}

	@Test
	public void testExceptionDuringClose() {
		@SuppressWarnings("resource") // We are testing the close() method
		final UnionInputStream u = new UnionInputStream();
		u.add(new ByteArrayInputStream(new byte[] { 1 }) {
			@Override
			public void close() throws IOException {
				throw new IOException("I AM A TEST");
			}
		});
		try {
			u.close();
			fail("close ignored inner stream exception");
		} catch (IOException e) {
			assertEquals("I AM A TEST", e.getMessage());
		}
	}

	@Test
	public void testNonBlockingPartialRead() throws Exception {
		InputStream errorReadStream = new InputStream() {
			@Override
			public int read() throws IOException {
				throw new IOException("Expected");
			}

			@Override
			public int read(byte b[], int off, int len) throws IOException {
				throw new IOException("Expected");
			}
		};
		try (UnionInputStream u = new UnionInputStream(
				new ByteArrayInputStream(new byte[] { 1, 2, 3 }),
				errorReadStream)) {
			byte buf[] = new byte[10];
			assertEquals(3, u.read(buf, 0, 10));
			assertTrue(Arrays.equals(new byte[] { 1, 2, 3 }, slice(buf, 3)));
			try {
				u.read(buf, 0, 1);
				fail("Expected exception from errorReadStream");
			} catch (IOException e) {
				assertEquals("Expected", e.getMessage());
			}
		}
	}
}
