001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.junit.bct.annotations; 018 019import static org.apache.juneau.commons.utils.ThrowableUtils.*; 020import static org.apache.juneau.commons.utils.Utils.*; 021import static org.apache.juneau.junit.bct.BctConfiguration.*; 022import static org.apache.juneau.commons.lang.TriState.*; 023 024import java.util.*; 025 026import org.apache.juneau.junit.bct.*; 027import org.junit.jupiter.api.extension.*; 028 029/** 030 * JUnit 5 extension that processes {@link BctConfig} annotations. 031 * 032 * <p> 033 * This extension automatically sets BCT settings before test execution and clears them after. 034 * It supports both class-level and method-level annotations, with method-level taking precedence. 035 */ 036public class BctConfigExtension implements BeforeEachCallback, AfterEachCallback { 037 038 @Override 039 public void beforeEach(ExtensionContext context) throws Exception { 040 var al = getAnnotations(context); 041 042 if (al.isEmpty()) 043 return; 044 045 clear(); 046 047 al.stream().map(x -> x.sortMaps()).filter(x -> neq(x, UNSET)).findFirst().ifPresent(x -> set(BCT_SORT_MAPS, x == TRUE)); 048 al.stream().map(x -> x.sortCollections()).filter(x -> neq(x, UNSET)).findFirst().ifPresent(x -> set(BCT_SORT_COLLECTIONS, x == TRUE)); 049 al.stream().map(x -> x.beanConverter()).filter(x -> neq(x, BeanConverter.class)).findFirst().map(x -> eq(x, BasicBeanConverter.class) ? null : x).ifPresent(x -> setConverter(x)); 050 } 051 052 private static void setConverter(Class<? extends BeanConverter> x) { 053 safe(()->{ 054 var c = x.getDeclaredConstructor(); 055 c.setAccessible(true); 056 set(c.newInstance()); 057 }, e -> rex(e, "Failed to instantiate BeanConverter: {0}. It must have a no-arg constructor.", x.getName())); 058 } 059 060 @Override 061 public void afterEach(ExtensionContext context) throws Exception { 062 var al = getAnnotations(context); 063 064 if (al.isEmpty()) 065 return; 066 067 clear(); 068 } 069 070 private static List<BctConfig> getAnnotations(ExtensionContext context) { 071 var l = new ArrayList<BctConfig>(); 072 context.getTestMethod().map(x -> x.getAnnotation(BctConfig.class)).ifPresent(x -> l.add(x)); 073 context.getTestClass().map(x -> x.getAnnotation(BctConfig.class)).ifPresent(x -> l.add(x)); 074 return l; 075 } 076}