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

fi.jumi.api.drivers.TestId Maven / Gradle / Ivy

There is a newer version: 0.5.437
Show newest version
// Copyright © 2011-2012, Esko Luontola 
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package fi.jumi.api.drivers;

import javax.annotation.concurrent.Immutable;
import java.io.Serializable;

/**
 * Uniquely identifies a single test in the tree of all tests. Immutable.
 */
@Immutable
public abstract class TestId implements Comparable, Serializable {

    public static final TestId ROOT = new Root();

    public static TestId of(int... path) {
        TestId node = ROOT;
        for (int index : path) {
            node = new Child(node, index);
        }
        return node;
    }

    private TestId() {
        // prevent everybody except the inner classes from extending this class
    }

    // inquiring

    public abstract boolean isRoot();

    public abstract boolean isFirstChild();

    public boolean isAncestorOf(TestId descendant) {
        if (descendant.isRoot()) {
            return false;
        }
        TestId parent = descendant.getParent();
        return this.equals(parent) || this.isAncestorOf(parent);
    }

    public boolean isDescendantOf(TestId ancestor) {
        return ancestor.isAncestorOf(this);
    }

    // accessing relatives

    public abstract TestId getParent();

    public TestId getFirstChild() {
        return new Child(this, 0);
    }

    public abstract TestId getNextSibling();

    // low-level operations

    public abstract int getIndex();

    private int[] getPath() {
        // TODO: make public? should then write explicit tests for it
        return getPath(0);
    }

    private int[] getPath(int depth) {
        if (isRoot()) {
            return new int[depth];
        }
        int[] path = getParent().getPath(depth + 1);
        path[path.length - 1 - depth] = getIndex();
        return path;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof TestId) {
            TestId that = (TestId) obj;
            if (this.isRoot() || that.isRoot()) {
                return this.isRoot() == that.isRoot();
            }
            return this.getIndex() == that.getIndex() && this.getParent().equals(that.getParent());
        }
        return false;
    }

    @Override
    public int hashCode() {
        // We use an algorithm similar to java.util.Arrays.hashCode()
        int hash = 1;
        for (TestId node = this; !node.isRoot(); node = node.getParent()) {
            hash = 31 * hash + node.getIndex();
        }
        return hash;
    }

    @Override
    public int compareTo(TestId that) {
        int[] thisPath = this.getPath();
        int[] thatPath = that.getPath();
        for (int i = 0; i < thisPath.length && i < thatPath.length; i++) {
            Integer thisIndex = thisPath[i];
            Integer thatIndex = thatPath[i];
            int comp = thisIndex.compareTo(thatIndex);
            if (comp != 0) {
                return comp;
            }
        }
        return thisPath.length - thatPath.length;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("TestId(");
        int[] path = getPath();
        for (int i = 0; i < path.length; i++) {
            int index = path[i];
            if (i > 0) {
                sb.append(", ");
            }
            sb.append(index);
        }
        sb.append(")");
        return sb.toString();
    }


    @Immutable
    private static class Root extends TestId {

        @Override
        public boolean isRoot() {
            return true;
        }

        @Override
        public boolean isFirstChild() {
            throw new UnsupportedOperationException("root is not a child");
        }

        @Override
        public TestId getParent() {
            throw new UnsupportedOperationException("root has no parent");
        }

        @Override
        public TestId getNextSibling() {
            throw new UnsupportedOperationException("root has no siblings");
        }

        @Override
        public int getIndex() {
            throw new UnsupportedOperationException("root has no index");
        }
    }

    @Immutable
    private static class Child extends TestId {

        private final TestId parent;
        private final int index;

        public Child(TestId parent, int index) {
            if (index < 0) {
                throw new IllegalArgumentException("illegal index: " + index);
            }
            this.parent = parent;
            this.index = index;
        }

        @Override
        public boolean isRoot() {
            return false;
        }

        @Override
        public boolean isFirstChild() {
            return index == 0;
        }

        @Override
        public TestId getParent() {
            return parent;
        }

        @Override
        public TestId getNextSibling() {
            return new Child(parent, index + 1);
        }

        @Override
        public int getIndex() {
            return index;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy