/*
 * Copyright (C) 2007 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 com.android.unit_tests;

import android.net.Credentials;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;

import java.io.FileDescriptor;
import java.io.IOException;

public class LocalSocketTest extends TestCase {

    @SmallTest
    public void testBasic() throws Exception {
        LocalServerSocket ss;
        LocalSocket ls;
        LocalSocket ls1;

        ss = new LocalServerSocket("com.android.unit_tests.LocalSocketTest");

        ls = new LocalSocket();

        ls.connect(new LocalSocketAddress("com.android.unit_tests.LocalSocketTest"));

        ls1 = ss.accept();

        // Test trivial read and write
        ls.getOutputStream().write(42);

        assertEquals(42, ls1.getInputStream().read());

        // Test getting credentials
        Credentials c = ls1.getPeerCredentials();

        MoreAsserts.assertNotEqual(0, c.getPid());

        // Test sending and receiving file descriptors
        ls.setFileDescriptorsForSend(
                new FileDescriptor[]{FileDescriptor.in});

        ls.getOutputStream().write(42);

        assertEquals(42, ls1.getInputStream().read());

        FileDescriptor[] out = ls1.getAncillaryFileDescriptors();

        assertEquals(1, out.length);

        // Test multible byte write and available()
        ls1.getOutputStream().write(new byte[]{0, 1, 2, 3, 4, 5}, 1, 5);

        assertEquals(1, ls.getInputStream().read());
        assertEquals(4, ls.getInputStream().available());

        byte[] buffer = new byte[16];
        int countRead;

        countRead = ls.getInputStream().read(buffer, 1, 15);

        assertEquals(4, countRead);
        assertEquals(2, buffer[1]);
        assertEquals(3, buffer[2]);
        assertEquals(4, buffer[3]);
        assertEquals(5, buffer[4]);

        // Try various array-out-of-bound cases
        try {
            ls.getInputStream().read(buffer, 1, 16);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        try {
            ls.getOutputStream().write(buffer, 1, 16);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        try {
            ls.getOutputStream().write(buffer, -1, 15);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        try {
            ls.getOutputStream().write(buffer, 0, -1);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        try {
            ls.getInputStream().read(buffer, -1, 15);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        try {
            ls.getInputStream().read(buffer, 0, -1);
            fail("expected exception");
        } catch (ArrayIndexOutOfBoundsException ex) {
            // excpected
        }

        // Try read of length 0
        ls.getOutputStream().write(42);
        countRead = ls1.getInputStream().read(buffer, 0, 0);
        assertEquals(0, countRead);
        assertEquals(42, ls1.getInputStream().read());

        ss.close();

        ls.close();

        // Try write on closed socket

        try {
            ls.getOutputStream().write(42);
            fail("expected exception");
        } catch (IOException ex) {
            // Expected
        }

        // Try read on closed socket

        try {
            ls.getInputStream().read();
            fail("expected exception");
        } catch (IOException ex) {
            // Expected
        }

        // Try write on socket whose peer has closed

        try {
            ls1.getOutputStream().write(42);
            fail("expected exception");
        } catch (IOException ex) {
            // Expected
        }

        // Try read on socket whose peer has closed

        assertEquals(-1, ls1.getInputStream().read());

        ls1.close();
    }
}
