package com.github.tinosteinort.beanrepository;

import org.junit.Assert;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class AliasTest {

    @Test(expected = RuntimeException.class)
    public void noAliasFound() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .build();

        repository.getBean(SomeServiceInterface.class);
    }

    @Test public void aliasFound() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .build();

        SomeServiceImpl service = repository.getBean(SomeServiceInterface.class);
        assertNotNull(service);
    }

    @Test public void aliasSingletonIsSame() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .build();

        SomeServiceImpl service = repository.getBean(SomeServiceImpl.class);
        SomeServiceImpl alias = repository.getBean(SomeServiceInterface.class);

        assertNotNull(service);
        assertNotNull(alias);

        Assert.assertTrue(service == alias);
    }

    @Test public void aliasBeanProviderDeliversSame() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .build();

        final Provider<SomeServiceImpl> provider = repository.getProvider(SomeServiceImpl.class);
        final Provider<SomeServiceImpl> aliasProvider = repository.getProvider(SomeServiceInterface.class);

        assertNotNull(provider);
        assertNotNull(aliasProvider);

        Assert.assertTrue(provider.get() == aliasProvider.get());
    }

    @Test public void twoAliasesForSameBean() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .alias(SomeSecondServiceInterface.class, SomeServiceImpl.class)
                .build();

        final SomeServiceInterface alias1 = repository.getBean(SomeServiceInterface.class);
        final SomeSecondServiceInterface alias2 = repository.getBean(SomeSecondServiceInterface.class);

        assertNotNull(alias1);
        assertNotNull(alias2);
        Assert.assertEquals(alias1, alias2);
        Assert.assertTrue(alias1 == alias2);
    }

    @Test(expected = Exception.class)
    public void denySameAliasClassMultipleTimes() {

        new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceImpl.class, SomeServiceImpl::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .build();
    }

    @Test public void aliasTriggersPostConstruct() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceWithPostConstructImpl.class, SomeServiceWithPostConstructImpl::new)
                .alias(SomeServiceWithPostConstructInterface.class, SomeServiceWithPostConstructImpl.class)
                .build();

        SomeServiceWithPostConstructImpl.initCounter = 0;
        Assert.assertEquals(0, SomeServiceWithPostConstructImpl.initCounter);

        repository.getBean(SomeServiceWithPostConstructInterface.class);
        Assert.assertEquals(1, SomeServiceWithPostConstructImpl.initCounter);
    }

    @Test public void aliasDoesntTriggerAdditionalPostConstruct() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singleton(SomeServiceWithPostConstructImpl.class, SomeServiceWithPostConstructImpl::new)
                .alias(SomeServiceWithPostConstructInterface.class, SomeServiceWithPostConstructImpl.class)
                .build();

        SomeServiceWithPostConstructImpl.initCounter = 0;
        Assert.assertEquals(0, SomeServiceWithPostConstructImpl.initCounter);

        repository.getBean(SomeServiceWithPostConstructImpl.class);
        Assert.assertEquals(1, SomeServiceWithPostConstructImpl.initCounter);

        repository.getBean(SomeServiceWithPostConstructInterface.class);
        Assert.assertEquals(1, SomeServiceWithPostConstructImpl.initCounter);
    }

    @Test public void aliasForFactory() {

        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()
                .singletonFactory(SomeServiceImpl.class, SomeServiceImplFactory::new)
                .alias(SomeServiceInterface.class, SomeServiceImpl.class)
                .build();

        final SomeServiceImpl service = repository.getBean(SomeServiceImpl.class);
        final SomeServiceInterface alias = repository.getBean(SomeServiceInterface.class);

        assertNotNull(service);
        assertNotNull(alias);

        assertEquals(service, alias);
        assertTrue(System.identityHashCode(service) == System.identityHashCode(alias));
    }
}

class SomeServiceImpl implements SomeServiceInterface, SomeSecondServiceInterface {

}

class SomeServiceImplFactory implements Factory<SomeServiceImpl> {

    @Override public SomeServiceImpl createInstance() {
        return new SomeServiceImpl();
    }
}

interface SomeServiceInterface {

}

interface SomeSecondServiceInterface {

}

class SomeServiceWithPostConstructImpl implements SomeServiceWithPostConstructInterface, PostConstructible {

    static int initCounter = 0;

    @Override public void onPostConstruct(final BeanRepository repository) {
        initCounter++;
    }
}

interface  SomeServiceWithPostConstructInterface {

}

@@ -5571,24 +5571,653 @@
 ias));%0A    %7D
+%0A%0A    @Test public void aliasAsReference() %7B%0A%0A        final BeanRepository repository = new BeanRepository.BeanRepositoryBuilder()%0A                .singleton(ReferencingAliasService.class, ReferencingAliasService::new, SomeServiceInterface.class)%0A                .singletonFactory(SomeServiceImpl.class, SomeServiceImplFactory::new)%0A                .alias(SomeServiceInterface.class, SomeServiceImpl.class)%0A                .build();%0A%0A        final ReferencingAliasService service = repository.getBean(ReferencingAliasService.class);%0A%0A        assertNotNull(service);%0A        assertNotNull(service.getSomeServiceInterface());%0A    %7D
 %0A%7D%0A%0Aclass So
@@ -6841,20 +6841,371 @@
 tructInterface %7B%0A%0A%7D%0A
+%0Aclass ReferencingAliasService %7B%0A%0A    private final SomeServiceInterface someServiceInterface;%0A%0A    public ReferencingAliasService(final SomeServiceInterface someServiceInterface) %7B%0A        this.someServiceInterface = someServiceInterface;%0A    %7D%0A%0A    public SomeServiceInterface getSomeServiceInterface() %7B%0A        return someServiceInterface;%0A    %7D%0A%7D

Add test