package priorityqueues; import org.assertj.core.api.AbstractObjectAssert; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * An assert class for your array heap that provides an assert method to check the heap invariant. */ public abstract class AbstractHeapMinPQAssert extends AbstractObjectAssert, ExtrinsicMinPQ> { public AbstractHeapMinPQAssert(ExtrinsicMinPQ actual, Class selfType) { super(actual, selfType); } protected abstract int extractStartIndex(ExtrinsicMinPQ actual); protected abstract List> extractHeap(ExtrinsicMinPQ actual); public AbstractHeapMinPQAssert isValid() { String message = getErrorMessageIfInvalid(); if (message != null) { this.as("invariant check") .failWithMessage(message); } return this; } protected String getErrorMessageIfInvalid() { List> heap = extractHeap(this.actual); int startIndex = extractStartIndex(this.actual); return getErrorMessageIfInvalid(heap, startIndex, startIndex + this.actual.size()); } static String getErrorMessageIfInvalid(List> heap, int startIndex, int endIndex) { if (heap.size() < endIndex) { return String.format("Heap's internal ArrayList size (%d) is too small for heap's contents? " + "(Expected at least %d.)", heap.size(), endIndex); } Map brokenIndices = new TreeMap<>(); for (int i = startIndex; i < endIndex; i++) { String message = checkIndex(heap, i, startIndex, endIndex); if (message != null) { brokenIndices.put(i, message); } } if (brokenIndices.isEmpty()) { return null; } StringBuilder b = new StringBuilder(); String nl = System.lineSeparator(); b.append("Heap invariants broken at:").append(nl); for (Map.Entry entry : brokenIndices.entrySet()) { b.append(" - index ").append(entry.getKey()) .append(" (").append(entry.getValue()).append(")").append(nl); } return b.toString().stripTrailing(); } private static final int NUM_CHILDREN = 2; private static String checkIndex(List> heap, int parentIndex, int startIndex, int endIndex) { PriorityNode parentNode = heap.get(parentIndex); int firstChildIndex = (parentIndex - startIndex + 1) * NUM_CHILDREN + startIndex - 1; int lastChildIndex = Math.min(NUM_CHILDREN + firstChildIndex, endIndex); if (parentNode == null || childrenOfIndexAreInvalid(heap, parentNode, firstChildIndex, lastChildIndex)) { List> children = (firstChildIndex < endIndex) ? heap.subList(firstChildIndex, lastChildIndex) : List.of(); return "is " + parentNode + "; has children: " + children.toString(); } return null; } private static boolean childrenOfIndexAreInvalid( List> heap, PriorityNode parentNode, int firstChildIndex, int lastChildIndex) { for (int childIndex = firstChildIndex; childIndex < lastChildIndex; childIndex++) { PriorityNode childNode = heap.get(childIndex); if (childNode == null || parentNode.getPriority() > childNode.getPriority()) { return true; } } return false; } }