package de.renew.util;

import java.io.IOException;
import java.io.ObjectInput;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

/**
 * This is a TestCase for the ClassSource.
 *
 */

@ExtendWith(MockitoExtension.class)
public class ClassSourceTest {

    @Mock
    ClassLoader classLoader;
    @Mock
    ObjectInput mockedInput;

    @BeforeEach
    void setUp() {
        classLoader = this.getClass().getClassLoader();
    }

    /**
     * Test that the {@link ClassSource#setClassLoader(ClassLoader)} function works.
     * @throws RuntimeException if the loading of the deserializer fails.
     */
    @Test
    public void testSetClassLoader() {
        ClassSource.setClassLoader(classLoader);
        assertEquals(classLoader, ClassSource.getClassLoader());

    }

    /**
     * Test that the {@link  ClassSource#setClassLoader(ClassLoader)} function executes.
     * without a failure in the try block, where the deserializer is loaded and set. (failure of this would
     * throw a {@link RuntimeException}).
     */
    @Test
    public void testSetClassLoaderExceptionBlock() {
        assertDoesNotThrow(() -> ClassSource.setClassLoader(classLoader));
    }

    /**
     * Tests that {@link ClassSource#readObject(ObjectInput)} works after {@link  ClassSource#setClassLoader(ClassLoader)}
     * has been called with a custom class loader. 
     * @throws IOException if the loaded deserializer has I/O operations failure.
     * @throws ClassNotFoundException if the loaded deserializer cannot find the Class.
     */
    @Test
    void testReadObjectAfterSetLoader() throws IOException, ClassNotFoundException {
        ClassSource.setClassLoader(classLoader);
        when(mockedInput.readObject()).thenReturn("ReadObject");
        assertEquals("ReadObject", ClassSource.readObject(mockedInput));
    }

}