Search in sources :

Example 1 with Test

use of org.ballerinalang.testerina.core.entity.Test in project ballerina by ballerina-lang.

the class TestAnnotationProcessor method process.

@Override
public void process(FunctionNode functionNode, List<AnnotationAttachmentNode> annotations) {
    // to avoid processing those, we have to have below check.
    if (!suite.getSuiteName().equals(functionNode.getPosition().getSource().getPackageName())) {
        return;
    }
    // traverse through the annotations of this function
    for (AnnotationAttachmentNode attachmentNode : annotations) {
        String annotationName = attachmentNode.getAnnotationName().getValue();
        String functionName = functionNode.getName().getValue();
        if (BEFORE_SUITE_ANNOTATION_NAME.equals(annotationName)) {
            suite.addBeforeSuiteFunction(functionName);
        } else if (AFTER_SUITE_ANNOTATION_NAME.equals(annotationName)) {
            suite.addAfterSuiteFunction(functionName);
        } else if (BEFORE_EACH_ANNOTATION_NAME.equals(annotationName)) {
            suite.addBeforeEachFunction(functionName);
        } else if (AFTER_EACH_ANNOTATION_NAME.equals(annotationName)) {
            suite.addAfterEachFunction(functionName);
        } else if (MOCK_ANNOTATION_NAME.equals(annotationName)) {
            String[] vals = new String[2];
            // If package property not present the package is .
            // TODO: when default values are supported in annotation struct we can remove this
            vals[0] = ".";
            if (attachmentNode.getExpression() instanceof BLangRecordLiteral) {
                List<BLangRecordLiteral.BLangRecordKeyValue> attributes = ((BLangRecordLiteral) attachmentNode.getExpression()).getKeyValuePairs();
                attributes.forEach(attributeNode -> {
                    String name = attributeNode.getKey().toString();
                    String value = attributeNode.getValue().toString();
                    if (PACKAGE.equals(name)) {
                        vals[0] = value;
                    } else if (FUNCTION.equals(name)) {
                        vals[1] = value;
                    }
                });
                suite.addMockFunction(vals[0] + MOCK_ANNOTATION_DELIMITER + vals[1], functionName);
            }
        } else if (TEST_ANNOTATION_NAME.equals(annotationName)) {
            Test test = new Test();
            test.setTestName(functionName);
            AtomicBoolean shouldSkip = new AtomicBoolean();
            AtomicBoolean groupsFound = new AtomicBoolean();
            List<String> groups = registry.getGroups();
            boolean shouldIncludeGroups = registry.shouldIncludeGroups();
            if (attachmentNode.getExpression() instanceof BLangRecordLiteral) {
                List<BLangRecordLiteral.BLangRecordKeyValue> attributes = ((BLangRecordLiteral) attachmentNode.getExpression()).getKeyValuePairs();
                attributes.forEach(attributeNode -> {
                    String name = attributeNode.getKey().toString();
                    // Check if enable property is present in the annotation
                    if (TEST_ENABLE_ANNOTATION_NAME.equals(name) && "false".equals(attributeNode.getValue().toString())) {
                        // If enable is false, disable the test, no further processing is needed
                        shouldSkip.set(true);
                        return;
                    }
                    // Check whether user has provided a group list
                    if (groups != null && !groups.isEmpty()) {
                        // check if groups attribute is present in the annotation
                        if (GROUP_ANNOTATION_NAME.equals(name)) {
                            if (attributeNode.getValue() instanceof BLangArrayLiteral) {
                                BLangArrayLiteral values = (BLangArrayLiteral) attributeNode.getValue();
                                boolean isGroupPresent = isGroupAvailable(groups, values.exprs.stream().map(node -> node.toString()).collect(Collectors.toList()));
                                if (shouldIncludeGroups) {
                                    // include only if the test belong to one of these groups
                                    if (!isGroupPresent) {
                                        // skip the test if this group is not defined in this test
                                        shouldSkip.set(true);
                                        return;
                                    }
                                } else {
                                    // exclude only if the test belong to one of these groups
                                    if (isGroupPresent) {
                                        // skip if this test belongs to one of the excluded groups
                                        shouldSkip.set(true);
                                        return;
                                    }
                                }
                                groupsFound.set(true);
                            }
                        }
                    }
                    if (VALUE_SET_ANNOTATION_NAME.equals(name)) {
                        test.setDataProvider(attributeNode.getValue().toString());
                    }
                    if (BEFORE_FUNCTION.equals(name)) {
                        test.setBeforeTestFunction(attributeNode.getValue().toString());
                    }
                    if (AFTER_FUNCTION.equals(name)) {
                        test.setAfterTestFunction(attributeNode.getValue().toString());
                    }
                    if (DEPENDS_ON_FUNCTIONS.equals(name)) {
                        if (attributeNode.getValue() instanceof BLangArrayLiteral) {
                            BLangArrayLiteral values = (BLangArrayLiteral) attributeNode.getValue();
                            values.exprs.stream().map(node -> node.toString()).forEach(test::addDependsOnTestFunction);
                        }
                    }
                });
            }
            if (groups != null && !groups.isEmpty() && !groupsFound.get() && shouldIncludeGroups) {
                // if the user has asked to run only a specific list of groups and this test doesn't have
                // that group, we should skip the test
                shouldSkip.set(true);
            }
            if (!shouldSkip.get()) {
                suite.addTests(test);
            }
        } else {
        // disregard this annotation
        }
    }
}
Also used : Arrays(java.util.Arrays) PackageNode(org.ballerinalang.model.tree.PackageNode) BType(org.ballerinalang.model.types.BType) ProgramFile(org.ballerinalang.util.codegen.ProgramFile) TestSuite(org.ballerinalang.testerina.core.entity.TestSuite) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BallerinaException(org.ballerinalang.util.exceptions.BallerinaException) BLangRecordLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral) DiagnosticLog(org.ballerinalang.util.diagnostic.DiagnosticLog) PackageInfo(org.ballerinalang.util.codegen.PackageInfo) ArrayList(java.util.ArrayList) SupportedAnnotationPackages(org.ballerinalang.compiler.plugins.SupportedAnnotationPackages) AbstractCompilerPlugin(org.ballerinalang.compiler.plugins.AbstractCompilerPlugin) Vector(java.util.Vector) Map(java.util.Map) TesterinaFunction(org.ballerinalang.testerina.core.entity.TesterinaFunction) BLangArrayLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangArrayLiteral) LinkedList(java.util.LinkedList) BLangPackage(org.wso2.ballerinalang.compiler.tree.BLangPackage) FunctionNode(org.ballerinalang.model.tree.FunctionNode) TypeTags(org.ballerinalang.model.types.TypeTags) Collectors(java.util.stream.Collectors) AnnotationAttachmentNode(org.ballerinalang.model.tree.AnnotationAttachmentNode) BArrayType(org.ballerinalang.model.types.BArrayType) List(java.util.List) Instruction(org.ballerinalang.util.codegen.Instruction) Test(org.ballerinalang.testerina.core.entity.Test) Queue(java.util.Queue) FunctionInfo(org.ballerinalang.util.codegen.FunctionInfo) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Test(org.ballerinalang.testerina.core.entity.Test) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) BLangArrayLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangArrayLiteral) BLangRecordLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral) AnnotationAttachmentNode(org.ballerinalang.model.tree.AnnotationAttachmentNode)

Example 2 with Test

use of org.ballerinalang.testerina.core.entity.Test in project ballerina by ballerina-lang.

the class TestAnnotationProcessor method checkCyclicDependencies.

private static int[] checkCyclicDependencies(List<Test> tests) {
    int numberOfNodes = tests.size();
    int[] indegrees = new int[numberOfNodes];
    int[] sortedElts = new int[numberOfNodes];
    List<Integer>[] dependencyMatrix = new ArrayList[numberOfNodes];
    for (int i = 0; i < numberOfNodes; i++) {
        dependencyMatrix[i] = new ArrayList<>();
    }
    List<String> testNames = tests.stream().map(k -> k.getTestName()).collect(Collectors.toList());
    int i = 0;
    for (Test test : tests) {
        if (!test.getDependsOnTestFunctions().isEmpty()) {
            for (String dependsOnFn : test.getDependsOnTestFunctions()) {
                int idx = testNames.indexOf(dependsOnFn);
                if (idx == -1) {
                    String message = String.format("Test [%s] depends on function [%s], but it couldn't be found" + ".", test.getTestFunction().getName(), dependsOnFn);
                    throw new BallerinaException(message);
                }
                dependencyMatrix[i].add(idx);
            }
        }
        i++;
    }
    // fill in degrees
    for (int j = 0; j < numberOfNodes; j++) {
        List<Integer> dependencies = dependencyMatrix[j];
        for (int node : dependencies) {
            indegrees[node]++;
        }
    }
    // Create a queue and enqueue all vertices with indegree 0
    Queue<Integer> q = new LinkedList<Integer>();
    for (i = 0; i < numberOfNodes; i++) {
        if (indegrees[i] == 0) {
            q.add(i);
        }
    }
    // Initialize count of visited vertices
    int cnt = 0;
    // Create a vector to store result (A topological ordering of the vertices)
    Vector<Integer> topOrder = new Vector<Integer>();
    while (!q.isEmpty()) {
        // Extract front of queue (or perform dequeue) and add it to topological order
        int u = q.poll();
        topOrder.add(u);
        // Iterate through all its neighbouring nodes of dequeued node u and decrease their in-degree by 1
        for (int node : dependencyMatrix[u]) {
            // If in-degree becomes zero, add it to queue
            if (--indegrees[node] == 0) {
                q.add(node);
            }
        }
        cnt++;
    }
    // Check if there was a cycle
    if (cnt != numberOfNodes) {
        String message = "Cyclic test dependency detected";
        throw new BallerinaException(message);
    }
    i = numberOfNodes - 1;
    for (int elt : topOrder) {
        sortedElts[i] = elt;
        i--;
    }
    return sortedElts;
}
Also used : Arrays(java.util.Arrays) PackageNode(org.ballerinalang.model.tree.PackageNode) BType(org.ballerinalang.model.types.BType) ProgramFile(org.ballerinalang.util.codegen.ProgramFile) TestSuite(org.ballerinalang.testerina.core.entity.TestSuite) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BallerinaException(org.ballerinalang.util.exceptions.BallerinaException) BLangRecordLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral) DiagnosticLog(org.ballerinalang.util.diagnostic.DiagnosticLog) PackageInfo(org.ballerinalang.util.codegen.PackageInfo) ArrayList(java.util.ArrayList) SupportedAnnotationPackages(org.ballerinalang.compiler.plugins.SupportedAnnotationPackages) AbstractCompilerPlugin(org.ballerinalang.compiler.plugins.AbstractCompilerPlugin) Vector(java.util.Vector) Map(java.util.Map) TesterinaFunction(org.ballerinalang.testerina.core.entity.TesterinaFunction) BLangArrayLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangArrayLiteral) LinkedList(java.util.LinkedList) BLangPackage(org.wso2.ballerinalang.compiler.tree.BLangPackage) FunctionNode(org.ballerinalang.model.tree.FunctionNode) TypeTags(org.ballerinalang.model.types.TypeTags) Collectors(java.util.stream.Collectors) AnnotationAttachmentNode(org.ballerinalang.model.tree.AnnotationAttachmentNode) BArrayType(org.ballerinalang.model.types.BArrayType) List(java.util.List) Instruction(org.ballerinalang.util.codegen.Instruction) Test(org.ballerinalang.testerina.core.entity.Test) Queue(java.util.Queue) FunctionInfo(org.ballerinalang.util.codegen.FunctionInfo) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Test(org.ballerinalang.testerina.core.entity.Test) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) BallerinaException(org.ballerinalang.util.exceptions.BallerinaException) Vector(java.util.Vector)

Example 3 with Test

use of org.ballerinalang.testerina.core.entity.Test in project ballerina by ballerina-lang.

the class TestAnnotationProcessor method packageProcessed.

/**
 * TODO this is a temporary solution, till we get a proper API from Ballerina Core.
 * This method will get executed at the completion of the processing of a ballerina package.
 *
 * @param programFile {@link ProgramFile} corresponds to the current ballerina package
 */
public void packageProcessed(ProgramFile programFile) {
    packageInit = false;
    // TODO the below line is required since this method is currently getting explicitly called from BTestRunner
    suite = TesterinaRegistry.getInstance().getTestSuites().get(programFile.getEntryPkgName());
    suite.setInitFunction(new TesterinaFunction(programFile, programFile.getEntryPackage().getInitFunctionInfo(), TesterinaFunction.Type.INIT));
    // add all functions of the package as utility functions
    Arrays.stream(programFile.getEntryPackage().getFunctionInfoEntries()).forEach(functionInfo -> {
        suite.addTestUtilityFunction(new TesterinaFunction(programFile, functionInfo, TesterinaFunction.Type.UTIL));
    });
    int[] testExecutionOrder = checkCyclicDependencies(suite.getTests());
    resolveFunctions(suite);
    List<Test> sortedTests = orderTests(suite.getTests(), testExecutionOrder);
    suite.setTests(sortedTests);
    suite.setProgramFile(programFile);
}
Also used : Test(org.ballerinalang.testerina.core.entity.Test) TesterinaFunction(org.ballerinalang.testerina.core.entity.TesterinaFunction)

Example 4 with Test

use of org.ballerinalang.testerina.core.entity.Test in project ballerina by ballerina-lang.

the class TestAnnotationProcessor method resolveFunctions.

/**
 * Resolve function names to {@link TesterinaFunction}s.
 *
 * @param suite {@link TestSuite} whose functions to be resolved.
 */
private static void resolveFunctions(TestSuite suite) {
    List<TesterinaFunction> functions = suite.getTestUtilityFunctions();
    List<String> functionNames = functions.stream().map(testerinaFunction -> testerinaFunction.getName()).collect(Collectors.toList());
    for (Test test : suite.getTests()) {
        if (test.getTestName() != null && functionNames.contains(test.getTestName())) {
            test.setTestFunction(functions.stream().filter(e -> e.getName().equals(test.getTestName())).findFirst().get());
        }
        if (test.getBeforeTestFunction() != null && functionNames.contains(test.getBeforeTestFunction())) {
            test.setBeforeTestFunctionObj(functions.stream().filter(e -> e.getName().equals(test.getBeforeTestFunction())).findFirst().get());
        }
        if (test.getAfterTestFunction() != null && functionNames.contains(test.getAfterTestFunction())) {
            test.setAfterTestFunctionObj(functions.stream().filter(e -> e.getName().equals(test.getAfterTestFunction())).findFirst().get());
        }
        if (test.getDataProvider() != null && functionNames.contains(test.getDataProvider())) {
            String dataProvider = test.getDataProvider();
            test.setDataProviderFunction(functions.stream().filter(e -> e.getName().equals(test.getDataProvider())).findFirst().map(func -> {
                // TODO these validations are not working properly with the latest refactoring
                if (func.getbFunction().getRetParamTypes().length == 1) {
                    BType bType = func.getbFunction().getRetParamTypes()[0];
                    if (bType.getTag() == TypeTags.ARRAY_TAG) {
                        BArrayType bArrayType = (BArrayType) bType;
                        if (bArrayType.getElementType().getTag() != TypeTags.ARRAY_TAG) {
                            String message = String.format("Data provider function [%s] should return an array of" + " arrays.", dataProvider);
                            throw new BallerinaException(message);
                        }
                    } else {
                        String message = String.format("Data provider function [%s] should return an array of " + "arrays.", dataProvider);
                        throw new BallerinaException(message);
                    }
                } else {
                    String message = String.format("Data provider function [%s] should have only one return type" + ".", dataProvider);
                    throw new BallerinaException(message);
                }
                return func;
            }).get());
            if (test.getDataProviderFunction() == null) {
                String message = String.format("Data provider function [%s] cannot be found.", dataProvider);
                throw new BallerinaException(message);
            }
        }
        for (String dependsOnFn : test.getDependsOnTestFunctions()) {
            // TODO handle missing func case
            test.addDependsOnTestFunction(functions.stream().filter(e -> e.getName().equals(dependsOnFn)).findFirst().get());
        }
    }
    // resolve mock functions
    suite.getMockFunctionNamesMap().forEach((id, functionName) -> {
        TesterinaFunction function = suite.getTestUtilityFunctions().stream().filter(e -> e.getName().equals(functionName)).findFirst().get();
        suite.addMockFunctionObj(id, function);
    });
    suite.getBeforeSuiteFunctionNames().forEach(functionName -> {
        TesterinaFunction function = suite.getTestUtilityFunctions().stream().filter(e -> e.getName().equals(functionName)).findFirst().get();
        suite.addBeforeSuiteFunctionObj(function);
    });
    suite.getAfterSuiteFunctionNames().forEach(functionName -> {
        TesterinaFunction function = suite.getTestUtilityFunctions().stream().filter(e -> e.getName().equals(functionName)).findFirst().get();
        suite.addAfterSuiteFunctionObj(function);
    });
    suite.getBeforeEachFunctionNames().forEach(functionName -> {
        TesterinaFunction function = suite.getTestUtilityFunctions().stream().filter(e -> e.getName().equals(functionName)).findFirst().get();
        suite.addBeforeEachFunctionObj(function);
    });
    suite.getAfterEachFunctionNames().forEach(functionName -> {
        TesterinaFunction function = suite.getTestUtilityFunctions().stream().filter(e -> e.getName().equals(functionName)).findFirst().get();
        suite.addAfterEachFunctionObj(function);
    });
}
Also used : Arrays(java.util.Arrays) PackageNode(org.ballerinalang.model.tree.PackageNode) BType(org.ballerinalang.model.types.BType) ProgramFile(org.ballerinalang.util.codegen.ProgramFile) TestSuite(org.ballerinalang.testerina.core.entity.TestSuite) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BallerinaException(org.ballerinalang.util.exceptions.BallerinaException) BLangRecordLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangRecordLiteral) DiagnosticLog(org.ballerinalang.util.diagnostic.DiagnosticLog) PackageInfo(org.ballerinalang.util.codegen.PackageInfo) ArrayList(java.util.ArrayList) SupportedAnnotationPackages(org.ballerinalang.compiler.plugins.SupportedAnnotationPackages) AbstractCompilerPlugin(org.ballerinalang.compiler.plugins.AbstractCompilerPlugin) Vector(java.util.Vector) Map(java.util.Map) TesterinaFunction(org.ballerinalang.testerina.core.entity.TesterinaFunction) BLangArrayLiteral(org.wso2.ballerinalang.compiler.tree.expressions.BLangArrayLiteral) LinkedList(java.util.LinkedList) BLangPackage(org.wso2.ballerinalang.compiler.tree.BLangPackage) FunctionNode(org.ballerinalang.model.tree.FunctionNode) TypeTags(org.ballerinalang.model.types.TypeTags) Collectors(java.util.stream.Collectors) AnnotationAttachmentNode(org.ballerinalang.model.tree.AnnotationAttachmentNode) BArrayType(org.ballerinalang.model.types.BArrayType) List(java.util.List) Instruction(org.ballerinalang.util.codegen.Instruction) Test(org.ballerinalang.testerina.core.entity.Test) Queue(java.util.Queue) FunctionInfo(org.ballerinalang.util.codegen.FunctionInfo) BArrayType(org.ballerinalang.model.types.BArrayType) Test(org.ballerinalang.testerina.core.entity.Test) BType(org.ballerinalang.model.types.BType) BallerinaException(org.ballerinalang.util.exceptions.BallerinaException) TesterinaFunction(org.ballerinalang.testerina.core.entity.TesterinaFunction)

Aggregations

Test (org.ballerinalang.testerina.core.entity.Test)4 TesterinaFunction (org.ballerinalang.testerina.core.entity.TesterinaFunction)4 ArrayList (java.util.ArrayList)3 Arrays (java.util.Arrays)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Map (java.util.Map)3 Queue (java.util.Queue)3 Vector (java.util.Vector)3 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)3 Collectors (java.util.stream.Collectors)3 AbstractCompilerPlugin (org.ballerinalang.compiler.plugins.AbstractCompilerPlugin)3 SupportedAnnotationPackages (org.ballerinalang.compiler.plugins.SupportedAnnotationPackages)3 AnnotationAttachmentNode (org.ballerinalang.model.tree.AnnotationAttachmentNode)3 FunctionNode (org.ballerinalang.model.tree.FunctionNode)3 PackageNode (org.ballerinalang.model.tree.PackageNode)3 BArrayType (org.ballerinalang.model.types.BArrayType)3 BType (org.ballerinalang.model.types.BType)3 TypeTags (org.ballerinalang.model.types.TypeTags)3 TestSuite (org.ballerinalang.testerina.core.entity.TestSuite)3