001/* 002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.test.generator.internal.net.java.quickcheck.generator.support; 017 018import de.cuioss.test.generator.internal.net.java.quickcheck.Generator; 019import de.cuioss.test.generator.internal.net.java.quickcheck.GeneratorException; 020 021import java.util.ArrayList; 022import java.util.List; 023 024/** 025 * Base class for tree generators. 026 * 027 * <p> 028 * The callback order is: 029 * </p> 030 * <ul> 031 * <li>{@link AbstractTreeGenerator#createNode()}: create current node</li> 032 * <li>{@link AbstractTreeGenerator#getChildCount(int, int)}: calculate number 033 * of child nodes</li> 034 * <li>(create child nodes)</li> 035 * <li>{@link AbstractTreeGenerator#addChildren(Object, List)}: add child nodes 036 * to node</li> 037 * </ul> 038 * 039 * @param <T> type of tree node 040 */ 041public abstract class AbstractTreeGenerator<T> implements Generator<T> { 042 043 public static final int MAX_TREE_DEPTH = 50; 044 045 /** 046 * Create a node of type T. 047 */ 048 protected abstract T createNode(); 049 050 /** 051 * Add the created children to the parent node. 052 */ 053 protected abstract void addChildren(T node, List<T> children); 054 055 /** 056 * Get the number of children for the current level. 057 * 058 * @param level current level starting with 0 for the root level 059 * @param numberOfSiblings number of siblings (number of siblings is 1 for the 060 * root node.) 061 */ 062 protected abstract int getChildCount(int level, int numberOfSiblings); 063 064 /** 065 * @return root node of the generated tree 066 */ 067 @Override 068 public T next() { 069 return createNodeAndAddChildren(-1, 1); 070 } 071 072 private List<T> down(int level, int numberOfSiblings) { 073 checkDepth(level); 074 List<T> result = new ArrayList<>(); 075 int childCount = getChildCount(level, numberOfSiblings); 076 for (int i = 0; i < childCount; i++) { 077 T node = createNodeAndAddChildren(level, childCount); 078 result.add(node); 079 } 080 return result; 081 } 082 083 private void checkDepth(int level) { 084 if (level > MAX_TREE_DEPTH) { 085 throw new GeneratorException("Max tree depth (%s) exceeded.".formatted(MAX_TREE_DEPTH), this); 086 } 087 } 088 089 private T createNodeAndAddChildren(int level, int numberOfSiblings) { 090 T node = createNode(); 091 addChildren(node, down(level + 1, numberOfSiblings)); 092 return node; 093 } 094 095}