package de.uni_hamburg.fs;

import org.junit.jupiter.api.Test;

import de.renew.util.Value;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class JavaFeatureTest {

    @Test
    void testGetValueWithPrimitiveType() {
        // given
        JavaFeature javaFeatureMock = mock(JavaFeature.class);
        Object testObject = new Object();
        int primitiveValue = 42;

        doReturn(int.class).when(javaFeatureMock).getJavaClass();
        when(javaFeatureMock.getObjectValue(testObject)).thenReturn(primitiveValue);
        when(javaFeatureMock.getValue(any())).thenCallRealMethod();

        // when
        Object result = javaFeatureMock.getValue(testObject);

        // then
        assertThat(result).isInstanceOf(Value.class);
        assertThat(((Value) result).value).isEqualTo(primitiveValue);
    }

    @Test
    void testGetValueWithNonPrimitiveType() {
        // given
        JavaFeature javaFeatureMock = mock(JavaFeature.class);
        Object testObject = new Object();
        String nonPrimitiveValue = "test";

        doReturn(String.class).when(javaFeatureMock).getJavaClass();
        when(javaFeatureMock.getObjectValue(testObject)).thenReturn(nonPrimitiveValue);
        when(javaFeatureMock.getValue(any())).thenCallRealMethod();

        // when
        Object result = javaFeatureMock.getValue(testObject);

        // then
        assertThat(result).isEqualTo(nonPrimitiveValue);
        assertThat(result).isNotInstanceOf(Value.class);
    }

    @Test
    void testGetValueWithException() {
        // given
        JavaFeature javaFeatureMock = mock(JavaFeature.class);
        Object testObject = new Object();
        Exception exceptionValue = new RuntimeException("Test exception");

        doReturn(int.class).when(javaFeatureMock).getJavaClass();
        when(javaFeatureMock.getObjectValue(testObject)).thenReturn(exceptionValue);
        when(javaFeatureMock.getValue(any())).thenCallRealMethod();

        // when
        Object result = javaFeatureMock.getValue(testObject);

        // then
        assertThat(result).isSameAs(exceptionValue);
        assertThat(result).isNotInstanceOf(Value.class);
    }

    @Test
    void testSetValueWithPrimitiveType() {
        // given
        JavaFeature javaFeatureMock = mock(JavaFeature.class);
        Object testObject = new Object();
        Value primitiveValue = new Value(42);

        doReturn(int.class).when(javaFeatureMock).getJavaClass();
        doCallRealMethod().when(javaFeatureMock).setValue(any(), any());

        // when
        javaFeatureMock.setValue(testObject, primitiveValue);

        // then
        verify(javaFeatureMock).setObjectValue(testObject, 42);
    }

    @Test
    void testSetValueWithNonPrimitiveType() {
        // given
        JavaFeature javaFeatureMock = mock(JavaFeature.class);
        Object testObject = new Object();
        String nonPrimitiveValue = "test";

        doReturn(String.class).when(javaFeatureMock).getJavaClass();
        doCallRealMethod().when(javaFeatureMock).setValue(any(), any());

        // when
        javaFeatureMock.setValue(testObject, nonPrimitiveValue);

        // then
        verify(javaFeatureMock).setObjectValue(testObject, nonPrimitiveValue);
    }
}