/*
 * Copyright 2002-2008 the original author or authors.
 *
 * 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 test.feature.plugin.context.componentscan;

import static org.junit.Assert.*;
import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.config.java.annotation.Bean;
import org.springframework.config.java.annotation.Configuration;
import org.springframework.config.java.context.JavaConfigApplicationContext;
import org.springframework.config.java.plugin.context.ComponentScan;
import test.common.beans.TestBean;
import test.common.dataaccess.DummyDataSource;
import test.feature.plugin.context.componentscan.scanpkg_2.JdbcBookRepository;


/** TODO: JAVADOC */
public class ComponentScanTests {

    @Test
    public void testComponentScanning() {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ScanConfig.class);
        assertExpectedBeansArePresent(ctx);
    }

    private void assertExpectedBeansArePresent(JavaConfigApplicationContext ctx) {
        assertTrue("should have contained bean named 'dataSource'", ctx.containsBean("dataSource"));
        assertTrue("should have contained bean named 'orderRepository'", ctx.containsBean("orderRepository"));
        assertTrue("should have contained bean named 'orderService'", ctx.containsBean("orderService"));
    }

    @Configuration
    @ComponentScan("test.feature.plugin.context.componentscan.scanpkg_1")
    static class ScanConfig {
        public @Bean DataSource dataSource() {
            return new DummyDataSource();
        }
    }


    @Test
    public void testComponentScanningWithAnnotationConfigOnByDefault() {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ScanConfigWithAnnotationConfigOn.class);
        assertTrue("should have contained bean named 'dataSource'", ctx.containsBean("dataSource"));
        assertTrue("should have contained bean named 'bookRepository'", ctx.containsBean("bookRepository"));
        assertNotNull("bookRepository.dataSource should have been autowired but was null", ctx.getBean(JdbcBookRepository.class).dataSource);
    }
    @Configuration
    @ComponentScan(value="test.feature.plugin.context.componentscan.scanpkg_2")
    static class ScanConfigWithAnnotationConfigOn {
        public @Bean DataSource dataSource() {
            return new DummyDataSource();
        }
    }


    @Test
    public void testComponentScanningWithAnnotationConfigOff() {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ScanConfigWithAnnotationConfigOff.class);
        assertTrue("should have contained bean named 'dataSource'", ctx.containsBean("dataSource"));
        assertTrue("should have contained bean named 'bookRepository'", ctx.containsBean("bookRepository"));
        assertNull("bookRepository.dataSource should have been null", ctx.getBean(JdbcBookRepository.class).dataSource);
    }
    @Configuration
    @ComponentScan(value="test.feature.plugin.context.componentscan.scanpkg_2", annotationConfig=false)
    static class ScanConfigWithAnnotationConfigOff {
        public @Bean DataSource dataSource() {
            return new DummyDataSource();
        }
    }


    /**
     * Ensures that SJC tolerates duplicate declarations of ComponentScan
     * across different Configuration classes.  XML tolerates this, and so
     * we should follow suit.
     */
    @Test
    public void testDuplicateComponentScanDeclarations() {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ScanConfig.class, ScanConfig2.class);
        assertExpectedBeansArePresent(ctx);
    }

    @Configuration
    @ComponentScan("test.feature.plugin.context.componentscan.scanpkg_1")
    static class ScanConfig2 {
        public @Bean TestBean dummy() { return new TestBean(); }
    }

    @Test
    public void testOtherFeatures() {
        JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ScanConfig.class, ScanConfig2.class);
        assertExpectedBeansArePresent(ctx);
    }

    // TODO: SJC-223
    // @Configuration
    // @ComponentScan(value = "test.feature.plugin.context.componentscan.scanpkg_1",
    //                annotationConfig = false,
    //                excludeFilters = {@Filter(type=FilterType.ANNOTATION, expression="")})
    // static class OtherFeatureConfig {
    //     public @Bean TestBean dummy() { return new TestBean(); }
    // }

}
