/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed 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 android.os.cts;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.Parcelable;
import android.os.cts.ParcelFileDescriptorPeer.FutureCloseListener;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;

import com.google.common.util.concurrent.AbstractFuture;

import junit.framework.ComparisonFailure;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.TimeUnit;

public class ParcelFileDescriptorTest extends AndroidTestCase {
    private static final long DURATION = 100l;

    public void testConstructorAndOpen() throws Exception {
        ParcelFileDescriptor tempFile = makeParcelFileDescriptor(getContext());

        ParcelFileDescriptor pfd = new ParcelFileDescriptor(tempFile);
        AutoCloseInputStream in = new AutoCloseInputStream(pfd);
        try {
            // read the data that was wrote previously
            assertEquals(0, in.read());
            assertEquals(1, in.read());
            assertEquals(2, in.read());
            assertEquals(3, in.read());
        } finally {
            in.close();
        }
    }

    private static class DoneSignal extends AbstractFuture<Void> {
        public boolean set() {
            return super.set(null);
        }

        @Override
        public boolean setException(Throwable t) {
            return super.setException(t);
        }
    }

    public void testFromSocket() throws Throwable {
        final int PORT = 12222;
        final int DATA = 1;

        final DoneSignal done = new DoneSignal();

        final Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ServerSocket ss;
                    ss = new ServerSocket(PORT);
                    Socket sSocket = ss.accept();
                    OutputStream out = sSocket.getOutputStream();
                    out.write(DATA);
                    Thread.sleep(DURATION);
                    out.close();
                    done.set();
                } catch (Exception e) {
                    done.setException(e);
                }
            }
        });
        t.start();

        Thread.sleep(DURATION);
        Socket socket;
        socket = new Socket(InetAddress.getLocalHost(), PORT);
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
        AutoCloseInputStream in = new AutoCloseInputStream(pfd);
        assertEquals(DATA, in.read());
        in.close();
        socket.close();
        pfd.close();

        done.get(5, TimeUnit.SECONDS);
    }

    public void testFromData() throws IOException {
        assertNull(ParcelFileDescriptor.fromData(null, null));
        byte[] data = new byte[] { 0 };
        assertFileDescriptorContent(data, ParcelFileDescriptor.fromData(data, null));
        data = new byte[] { 0, 1, 2, 3 };
        assertFileDescriptorContent(data, ParcelFileDescriptor.fromData(data, null));

        // Check that modifying the data does not modify the data in the FD
        data = new byte[] { 0, 1, 2, 3 };
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromData(data, null);
        data[1] = 42;
        assertFileDescriptorContent(new byte[] { 0, 1, 2, 3 }, pfd);
    }

    private static void assertFileDescriptorContent(byte[] expected, ParcelFileDescriptor fd)
        throws IOException {
        assertInputStreamContent(expected, new ParcelFileDescriptor.AutoCloseInputStream(fd));
    }

    private static void assertInputStreamContent(byte[] expected, InputStream is)
            throws IOException {
        try {
            byte[] observed = new byte[expected.length];
            int count = is.read(observed);
            assertEquals(expected.length, count);
            assertEquals(-1, is.read());
            MoreAsserts.assertEquals(expected, observed);
        } finally {
            is.close();
        }
    }

    public void testFromDataSkip() throws IOException {
        byte[] data = new byte[] { 40, 41, 42, 43, 44, 45, 46 };
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromData(data, null);
        assertNotNull(pfd);
        FileDescriptor fd = pfd.getFileDescriptor();
        assertNotNull(fd);
        assertTrue(fd.valid());
        FileInputStream is = new FileInputStream(fd);
        try {
            assertEquals(1, is.skip(1));
            assertEquals(41, is.read());
            assertEquals(42, is.read());
            assertEquals(2, is.skip(2));
            assertEquals(45, is.read());
            assertEquals(46, is.read());
            assertEquals(-1, is.read());
        } finally {
            is.close();
        }
    }

    public void testToString() {
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
        assertNotNull(pfd.toString());
    }

    public void testWriteToParcel() throws Exception {
        ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());

        Parcel pl = Parcel.obtain();
        pf.writeToParcel(pl, ParcelFileDescriptor.PARCELABLE_WRITE_RETURN_VALUE);
        pl.setDataPosition(0);
        ParcelFileDescriptor pfd = ParcelFileDescriptor.CREATOR.createFromParcel(pl);
        AutoCloseInputStream in = new AutoCloseInputStream(pfd);
        try {
            // read the data that was wrote previously
            assertEquals(0, in.read());
            assertEquals(1, in.read());
            assertEquals(2, in.read());
            assertEquals(3, in.read());
        } finally {
            in.close();
        }
    }

    public void testClose() throws Exception {
        ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());
        AutoCloseInputStream in1 = new AutoCloseInputStream(pf);
        try {
            assertEquals(0, in1.read());
        } finally {
            in1.close();
        }

        pf.close();

        AutoCloseInputStream in2 = new AutoCloseInputStream(pf);
        try {
            assertEquals(0, in2.read());
            fail("Failed to throw exception.");
        } catch (Exception e) {
            // expected
        } finally {
            in2.close();
        }
    }

    public void testGetStatSize() throws Exception {
        ParcelFileDescriptor pf = makeParcelFileDescriptor(getContext());
        assertTrue(pf.getStatSize() >= 0);
    }

    public void testGetFileDescriptor() {
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
        assertNotNull(pfd.getFileDescriptor());

        ParcelFileDescriptor p = new ParcelFileDescriptor(pfd);
        assertSame(pfd.getFileDescriptor(), p.getFileDescriptor());
    }

    public void testDescribeContents() {
        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
        assertTrue((Parcelable.CONTENTS_FILE_DESCRIPTOR & pfd.describeContents()) != 0);
    }

    private static void assertContains(String expected, String actual) {
        if (actual.contains(expected)) return;
        throw new ComparisonFailure("", expected, actual);
    }

    private static void write(ParcelFileDescriptor pfd, int oneByte)  throws IOException{
        new FileOutputStream(pfd.getFileDescriptor()).write(oneByte);
    }

    // This method is unlikely to be used by clients, as clients use ContentResolver,
    // which builds AutoCloseInputStream under the hood rather than FileInputStream
    // built from a raw FD.
    //
    // Using new FileInputStream(PFD.getFileDescriptor()) is discouraged, as error
    // propagation is lost, and read() will never throw IOException in such case.
    private static int read(ParcelFileDescriptor pfd) throws IOException {
        return new FileInputStream(pfd.getFileDescriptor()).read();
    }

    public void testPipeNormal() throws Exception {
        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
        final ParcelFileDescriptor red = pipe[0];
        final ParcelFileDescriptor blue = pipe[1];

        write(blue, 1);
        assertEquals(1, read(red));

        blue.close();
        assertEquals(-1, read(red));
        red.checkError();
    }

    // Reading should be done via AutoCloseInputStream if possible, rather than
    // recreating a FileInputStream from a raw FD, what's done in read(PFD).
    public void testPipeError_Discouraged() throws Exception {
        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
        final ParcelFileDescriptor red = pipe[0];
        final ParcelFileDescriptor blue = pipe[1];

        write(blue, 2);
        blue.closeWithError("OMG MUFFINS");

        // Even though closed we should still drain pipe.
        assertEquals(2, read(red));
        assertEquals(-1, read(red));
        try {
            red.checkError();
            fail("expected throw!");
        } catch (IOException e) {
            assertContains("OMG MUFFINS", e.getMessage());
        }
    }

    public void testPipeError() throws Exception {
        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
        final ParcelFileDescriptor red = pipe[0];
        final ParcelFileDescriptor blue = pipe[1];

        write(blue, 2);
        blue.closeWithError("OMG MUFFINS");

        try (AutoCloseInputStream is = new AutoCloseInputStream(red)) {
            is.read();
            is.read();  // Checks errors on EOF.
            fail("expected throw!");
        } catch (IOException e) {
            assertContains("OMG MUFFINS", e.getMessage());
        }
    }

    public void testFileNormal() throws Exception {
        final Handler handler = new Handler(Looper.getMainLooper());
        final FutureCloseListener listener = new FutureCloseListener();
        final ParcelFileDescriptor file = ParcelFileDescriptor.open(
                File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
                listener);

        write(file, 7);
        file.close();

        // make sure we were notified
        assertEquals(null, listener.get());
    }

    public void testFileError() throws Exception {
        final Handler handler = new Handler(Looper.getMainLooper());
        final FutureCloseListener listener = new FutureCloseListener();
        final ParcelFileDescriptor file = ParcelFileDescriptor.open(
                File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
                listener);

        write(file, 8);
        file.closeWithError("OMG BANANAS");

        // make sure error came through
        assertContains("OMG BANANAS", listener.get().getMessage());
    }

    public void testFileDetach() throws Exception {
        final Handler handler = new Handler(Looper.getMainLooper());
        final FutureCloseListener listener = new FutureCloseListener();
        final ParcelFileDescriptor file = ParcelFileDescriptor.open(
                File.createTempFile("pfd", "bbq"), ParcelFileDescriptor.MODE_READ_WRITE, handler,
                listener);

        file.detachFd();

        // make sure detach came through
        assertContains("DETACHED", listener.get().getMessage());
    }

    public void testSocketErrorAfterClose() throws Exception {
        final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createReliableSocketPair();
        final ParcelFileDescriptor red = pair[0];
        final ParcelFileDescriptor blue = pair[1];

        // both sides throw their hands in the air
        blue.closeWithError("BLUE RAWR");
        red.closeWithError("RED RAWR");

        // red noticed the blue error, but after that the comm pipe was dead so
        // blue had no way of seeing the red error.
        try {
            red.checkError();
            fail("expected throw!");
        } catch (IOException e) {
            assertContains("BLUE RAWR", e.getMessage());
        }

        // expected to not throw; no error
        blue.checkError();
    }

    public void testSocketMultipleCheck() throws Exception {
        final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createReliableSocketPair();
        final ParcelFileDescriptor red = pair[0];
        final ParcelFileDescriptor blue = pair[1];

        // allow checking before closed; they should all pass
        blue.checkError();
        blue.checkError();
        blue.checkError();

        // and verify we actually see it
        red.closeWithError("RAWR RED");
        try {
            blue.checkError();
            fail("expected throw!");
        } catch (IOException e) {
            assertContains("RAWR RED", e.getMessage());
        }
    }

    // http://b/21578056
    public void testFileNamesWithNonBmpChars() throws Exception {
        final File file = File.createTempFile("treble_clef_\ud834\udd1e", ".tmp");
        final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
                ParcelFileDescriptor.MODE_READ_ONLY);
        assertNotNull(pfd);
        pfd.close();
    }

    static ParcelFileDescriptor makeParcelFileDescriptor(Context con) throws Exception {
        final String fileName = "testParcelFileDescriptor";

        FileOutputStream fout = null;

        fout = con.openFileOutput(fileName, Context.MODE_PRIVATE);

        try {
            fout.write(new byte[] { 0x0, 0x1, 0x2, 0x3 });
        } finally {
            fout.close();
        }

        File dir = con.getFilesDir();
        File file = new File(dir, fileName);
        ParcelFileDescriptor pf = null;

        pf = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);

        return pf;
    }
}
