001/*
002 * Licensed to the author 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 de.cuioss.test.generator.internal.net.java.quickcheck.generator.support;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import de.cuioss.test.generator.internal.net.java.quickcheck.Generator;
023import de.cuioss.test.generator.internal.net.java.quickcheck.GeneratorException;
024
025/**
026 * Base class for tree generators.
027 *
028 * <p>
029 * The callback order is:
030 * </p>
031 * <ul>
032 * <li>{@link AbstractTreeGenerator#createNode()}: create current node</li>
033 * <li>{@link AbstractTreeGenerator#getChildCount(int, int)}: calculate number
034 * of child nodes</li>
035 * <li>(create child nodes)</li>
036 * <li>{@link AbstractTreeGenerator#addChildren(Object, List)}: add child nodes
037 * to node</li>
038 * </ul>
039 *
040 * @param <T> type of tree node
041 */
042public abstract class AbstractTreeGenerator<T> implements Generator<T> {
043
044    public static final int MAX_TREE_DEPTH = 50;
045
046    /**
047     * Create a node of type T.
048     */
049    protected abstract T createNode();
050
051    /**
052     * Add the created children to the parent node.
053     */
054    protected abstract void addChildren(T node, List<T> children);
055
056    /**
057     * Get the number of children for the current level.
058     *
059     * @param level            current level starting with 0 for the root level
060     * @param numberOfSiblings number of siblings (number of siblings is 1 for the
061     *                         root node.)
062     */
063    protected abstract int getChildCount(int level, int numberOfSiblings);
064
065    /**
066     * @return root node of the generated tree
067     */
068    @Override
069    public T next() {
070        return createNodeAndAddChildren(-1, 1);
071    }
072
073    private List<T> down(int level, int numberOfSiblings) {
074        checkDepth(level);
075        List<T> result = new ArrayList<>();
076        int childCount = getChildCount(level, numberOfSiblings);
077        for (int i = 0; i < childCount; i++) {
078            T node = createNodeAndAddChildren(level, childCount);
079            result.add(node);
080        }
081        return result;
082    }
083
084    private void checkDepth(int level) {
085        if (level > MAX_TREE_DEPTH) {
086            throw new GeneratorException("Max tree depth (%s) exceeded.".formatted(MAX_TREE_DEPTH), this);
087        }
088    }
089
090    private T createNodeAndAddChildren(int level, int numberOfSiblings) {
091        T node = createNode();
092        addChildren(node, down(level + 1, numberOfSiblings));
093        return node;
094    }
095
096}