All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.societegenerale.commons.plugin.rules.TestClassesNamingRuleTest Maven / Gradle / Ivy

package com.societegenerale.commons.plugin.rules;

import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.societegenerale.commons.plugin.service.ScopePathProvider;
import com.societegenerale.commons.plugin.utils.ArchUtils;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import org.junit.Test;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

/**
 * This rule raises an issue when a test class name does not match the provided
 * regular expression.
 * 
 * @see Test
 *      Classes should comply with a naming convention.
 * 
 * 
 */

public class TestClassesNamingRuleTest implements ArchRuleTest {

	private static final String TEST_CLASSES_NAMING_REGEX = "^((Test|IT)[a-zA-Z0-9]+|[A-Z][a-zA-Z0-9]*(Test|Tests|IT|TestCase|ITCase))$";

	private static final Pattern TEST_CLASSES_NAMING_PATTERN = Pattern.compile(TEST_CLASSES_NAMING_REGEX);

	public static final String TEST_CLASS_VIOLATION_MESSAGE = "Test classes should comply with a naming convention";

	@Override
	public void execute(String packagePath, ScopePathProvider scopePathProvider, Collection excludedPaths) {

		classes().that(haveAMethodAnnotatedWithTest).should(respectNamingConvention()).check(
				ArchUtils.importAllClassesInPackage(scopePathProvider.getTestClassesPath(), packagePath, excludedPaths));

	}

	private DescribedPredicate haveAMethodAnnotatedWithTest = new DescribedPredicate(
			"have a method annotated with @Test") {
		@Override
		public boolean apply(JavaClass input) {

			return isTestClass(input);

		}

		private boolean isTestClass(JavaClass input) {

			/*
			 * 
			 * This code works here
			 * 
			 * 
			 * 
			 * public class ClassTestWithIncorrectName2 {
			 * 
			 * @Nested class PositiveCase {
			 * 
			 * @Test public void check() { }
			 * 
			 * }
			 * 
			 * }
			 * 
			 * ----------------------------------
			 * 
			 * But not there
			 * 
			 * public class ClassTestWithIncorrectName2 {
			 * 
			 * @Nested class PositiveCase {
			 * 
			 * @Nested class PositiveCase1 {
			 * 
			 * @Test public void check() { }
			 * 
			 * }
			 * 
			 * }
			 * 
			 * }
			 * 
			 * 
			 * ------
			 * 
			 * Recursion looks like the solution
			 * 
			 */

			// Getting Inner Classes using Java Core

			Class[] innerClasses = input.reflect().getDeclaredClasses();

			if (innerClasses.length == 0) {
				return isThereAtLeastOneMethodAnnotedWithTest(input);

			} else {

				// Converting Inner Classes into JavaClasses to use Arch Unit API

				JavaClasses javaInnerClasses = new ClassFileImporter().importClasses(Arrays.asList(innerClasses));

				Set testClasses = javaInnerClasses.stream()
						.filter(this::isThereAtLeastOneMethodAnnotedWithTest).collect(Collectors.toSet());

				if (testClasses.isEmpty()) {

					return false;

				} else {

					return true;
				}

			}

		}

		private boolean isThereAtLeastOneMethodAnnotedWithTest(JavaClass javaClass) {

			// Check if the list of methods annoted with @Test is not empty

			return !javaClass.getMethods().stream().filter(this::isAnnotedWithTest).collect(Collectors.toSet())
					.isEmpty();

		}

		private boolean isAnnotedWithTest(JavaMethod method) {

			return method.isAnnotatedWith(Test.class);
		}
	};

	private ArchCondition respectNamingConvention() {

		return new ArchCondition("comply with a naming convention") {

			@Override

			public void check(JavaClass item, ConditionEvents events) {

				if (isInCorrect(item)) {

					events.add(SimpleConditionEvent.violated(item,
							TEST_CLASS_VIOLATION_MESSAGE + " - class: " + item.getName()));
				}

			}

			private boolean isInCorrect(JavaClass javaClass) {

				return !TEST_CLASSES_NAMING_PATTERN.matcher(javaClass.getSimpleName()).matches();

			}

		};

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy