/*
 * testvertex.cpp --
 *
 * Tests of the e4_Vertex class.
 *
 * Copyright (c) 2000-2003, JYL Software Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#ifndef	_WIN32
#include <unistd.h>
#endif
#include "test.h"

#define VF_VERTEXLIMIT	256

static int
test_vertex1()
{
    e4_Node n;
    e4_Vertex f;
    e4_Value v;
    int i = 0, j = 0, rank = 0;

    /*
     * Get the value stored in a vertex using e4_Vertex::Get, with an e4_Value.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex1 failed (step 0)\n");
	    return 1;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex1 failed (step 1)\n");
	    return 1;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex1 failed (step 2)\n");
	    return 1;
	}
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
            switch ((e4_VertexType) j) {
            case E4_VTNODE:
            case E4_VTINT:
                if (!n.AddVertex("f1", E4_IOLAST, rank, i)) {
                    fprintf(stderr, "test vertex1 failed (step 6.1.%d)\n", i);
                    return 1;
                }
                break;
            case E4_VTDOUBLE:
                if (!n.AddVertex("f1", E4_IOLAST, rank, (double) 3.145678)) {
                    fprintf(stderr, "test vertex1 failed (step 6.1.%d)\n", i);
                    return 1;
                }
                break;
            case E4_VTSTRING:
                if (!n.AddVertex("f1", E4_IOLAST, rank, "hello there")) {
                    fprintf(stderr, "test vertex1 failed (step 6.1.%d)\n", i);
                    return 1;
                }
                break;
            case E4_VTBINARY:
                if (!n.AddVertex("f1", E4_IOLAST, rank,
                                (const void *) "hello there", 12)) {
                    fprintf(stderr, "test vertex1 failed (step 6.1.%d)\n", i);
                    return 1;
                }
                break;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
	    if (j == (int) E4_VTNODE) {
		j = (int) E4_VTINT;
	    }
	    if (!n.GetVertexRefByRank(i + 1, f)) {
	        fprintf(stderr, "test vertex1 failed (step 7.1.%d)\n", i);
		return 1;
	    }
	    if (!f.IsValid()) {
		fprintf(stderr, "test vertex1 failed (step 7.2.%d)\n", i);
		return 1;
	    }
	    if (!f.Get(v)) {
	        fprintf(stderr, "test vertex1 failed (step 7.3.%d)\n", i);
		return 1;
	    }
	    if (v.vertexType != (e4_VertexType) j) {
		fprintf(stderr, "test vertex1 failed (step 7.4.%d)\n",
			i);
		return 1;
	    }
            switch ((e4_VertexType) j) {
            case E4_VTINT:
		if (v.u.i != i) {
		    fprintf(stderr, "test vertex1 failed (step 7.5.%d)\n", i);
		    return 1;
		}
		break;
            case E4_VTDOUBLE:
                break;
            case E4_VTSTRING:
	        if (strcmp(v.u.s, "hello there") != 0) {
		    fprintf(stderr, "test vertex1 failed (step 7.5.%d)\n", i);
		    return 1;
		}
                break;
            case E4_VTBINARY:
	        if ((strcmp((char *) v.u.b.bytes, "hello there") != 0) ||
		    (v.u.b.nbytes != 12)) {
		    fprintf(stderr, "test vertex1 failed (step 7.5.%d)\n", i);
		    return 1;
		}
                break;
            }
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex1 failed (step 8)\n");
	    return 1;
	}
    }

    return 0;
}

static int
test_vertex2()
{
    e4_Node n;
    e4_Vertex f;
    int i = 0, j = 0, k = 0, rank = 0, nbytes = 0;
    double ff = 0.0;
    const char *ss;
    const void *bytes;

    /*
     * Get the value stored in a vertex using e4_Vertex::Get, with an e4_Value.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex2 failed (step 0)\n");
	    return 2;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex2 failed (step 1)\n");
	    return 2;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex2 failed (step 2)\n");
	    return 2;
	}
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
            switch ((e4_VertexType) j) {
            case E4_VTNODE:
            case E4_VTINT:
                if (!n.AddVertex("f1", E4_IOLAST, rank, i)) {
                    fprintf(stderr, "test vertex2 failed (step 6.1.%d)\n", i);
                    return 2;
                }
                break;
            case E4_VTDOUBLE:
                if (!n.AddVertex("f1", E4_IOLAST, rank, (double) 3.145678)) {
                    fprintf(stderr, "test vertex2 failed (step 6.1.%d)\n", i);
                    return 2;
                }
                break;
            case E4_VTSTRING:
                if (!n.AddVertex("f1", E4_IOLAST, rank, "hello there")) {
                    fprintf(stderr, "test vertex2 failed (step 6.1.%d)\n", i);
                    return 2;
                }
                break;
            case E4_VTBINARY:
                if (!n.AddVertex("f1", E4_IOLAST, rank,
                                (const void *) "hello there", 12)) {
                    fprintf(stderr, "test vertex2 failed (step 6.1.%d)\n", i);
                    return 2;
                }
                break;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
	    if (j == (int) E4_VTNODE) {
		j = (int) E4_VTINT;
	    }
	    if (!n.GetVertexRefByRank(i + 1, f)) {
	        fprintf(stderr, "test vertex2 failed (step 7.1.%d)\n", i);
		return 2;
	    }
	    if (!f.IsValid()) {
		fprintf(stderr, "test vertex2 failed (step 7.2.%d)\n", i);
		return 2;
	    }
            switch ((e4_VertexType) j) {
            case E4_VTINT:
	        if (!f.Get(k)) {
		    fprintf(stderr, "test vertex2 failed (step 7.5.%d)\n", i);
		    return 2;
		}
		if (k != i) {
		    fprintf(stderr, "test vertex2 failed (step 7.6.%d)\n", i);
		    return 2;
		}
		break;
            case E4_VTDOUBLE:
	        if (!f.Get(ff)) {
		    fprintf(stderr, "test vertex2 failed (step 7.5.%d)\n", i);
		    return 2;
		}
                break;
            case E4_VTSTRING:
		if (!f.Get(ss)) {
		    fprintf(stderr, "test vertex2 failed (step 7.5.%d)\n", i);
		    return 2;
		}
	        if (strcmp(ss, "hello there") != 0) {
		    fprintf(stderr, "test vertex2 failed (step 7.6.%d)\n", i);
		    return 2;
		}
                break;
            case E4_VTBINARY:
	        if (!f.Get(bytes, nbytes)) {
		    fprintf(stderr, "test vertex2 failed (step 7.5.%d)\n", i);
		    return 2;
		}
	        if ((strcmp((char *) bytes, "hello there") != 0) ||
		    (nbytes != 12)) {
		    fprintf(stderr, "test vertex2 failed (step 7.5.%d)\n", i);
		    return 2;
		}
                break;
            }
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex2 failed (step 8)\n");
	    return 2;
	}
    }

    return 0;
}

static int
test_vertex3()
{
    e4_Node n;
    e4_Vertex f;
    int i = 0, j = 0, k = 0, rank = 0, nbytes = 0;
    double ff = 0.0;
    const char *ss;
    const void *bytes;

    /*
     * Set the value of a vertex using e4_Vertex::Set, get it back using
     * e4_Node::GetVertex.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex3 failed (step 0)\n");
	    return 3;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex3 failed (step 1)\n");
	    return 3;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex3 failed (step 2)\n");
	    return 3;
	}
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
            switch ((e4_VertexType) j) {
            case E4_VTNODE:
            case E4_VTINT:
                if (!n.AddVertex("f1", E4_IOLAST, rank, i)) {
                    fprintf(stderr, "test vertex3 failed (step 6.1.%d)\n", i);
                    return 3;
                }
                break;
            case E4_VTDOUBLE:
                if (!n.AddVertex("f1", E4_IOLAST, rank, (double) 3.145678)) {
                    fprintf(stderr, "test vertex3 failed (step 6.1.%d)\n", i);
                    return 3;
                }
                break;
            case E4_VTSTRING:
                if (!n.AddVertex("f1", E4_IOLAST, rank, "hello there")) {
                    fprintf(stderr, "test vertex3 failed (step 6.1.%d)\n", i);
                    return 3;
                }
                break;
            case E4_VTBINARY:
                if (!n.AddVertex("f1", E4_IOLAST, rank,
                                (const void *) "hello there", 12)) {
                    fprintf(stderr, "test vertex3 failed (step 6.1.%d)\n", i);
                    return 3;
                }
                break;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
            j = i % (int) E4_VTLASTVERTEXTYPE;
	    if (j == (int) E4_VTNODE) {
		j = (int) E4_VTINT;
	    }
	    if (!n.GetVertexRefByRank(i + 1, f)) {
	        fprintf(stderr, "test vertex3 failed (step 7.1.%d)\n", i);
		return 3;
	    }
	    if (!f.IsValid()) {
		fprintf(stderr, "test vertex3 failed (step 7.2.%d)\n", i);
		return 3;
	    }
            switch ((e4_VertexType) j) {
            case E4_VTINT:
                if (!f.Set(33)) {
		    fprintf(stderr, "test vertex3 failed (step 7.5.%d)\n", i);
		    return 3;
		}
                if (!n.GetVertexByRank(i + 1, k)) {
                    fprintf(stderr, "test vertex3 failed (step 7.6.%d)\n", i);
                    return 3;
                }
		if (k != 33) {
		    fprintf(stderr, "test vertex3 failed (step 7.7.%d)\n", i);
		    return 3;
		}
		break;
            case E4_VTDOUBLE:
                if (!f.Set((double) 12.3456)) {
		    fprintf(stderr, "test vertex3 failed (step 7.5.%d)\n", i);
		    return 3;
		}
                if (!n.GetVertexByRank(i + 1, ff)) {
                    fprintf(stderr, "test vertex3 failed (step 7.6.%d)\n", i);
                    return 3;
                }
                break;
            case E4_VTSTRING:
                if (!f.Set("goodbye, now")) {
		    fprintf(stderr, "test vertex3 failed (step 7.5.%d)\n", i);
		    return 3;
		}
                if (!n.GetVertexByRank(i + 1, ss)) {
                    fprintf(stderr, "test vertex3 failed (step 7.6.%d)\n", i);
                    return 3;
                }
	        if (strcmp(ss, "goodbye, now") != 0) {
		    fprintf(stderr, "test vertex3 failed (step 7.7.%d)\n", i);
		    return 3;
		}
                break;
            case E4_VTBINARY:
                if (!f.Set((const void *) "goodbye, now", 13)) {
		    fprintf(stderr, "test vertex3 failed (step 7.5.%d)\n", i);
		    return 3;
		}
                if (!n.GetVertexByRank(i + 1, bytes, nbytes)) {
                    fprintf(stderr, "test vertex3 failed (step 7.6.%d)\n", i);
                    return 3;
                }
	        if ((strcmp((char *) bytes, "goodbye, now") != 0) ||
		    (nbytes != 13)) {
		    fprintf(stderr, "test vertex3 failed (step 7.7.%d)\n", i);
		    return 3;
		}
                break;
            }
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex3 failed (step 8)\n");
	    return 3;
	}
    }

    return 0;
}

static int
test_vertex4()
{
    e4_Node n1, n2, n3;
    e4_Vertex f;
    int rank = 0;

    /*
     * Test e4_Vertex::Get with a node value.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex4 failed (step 0)\n");
	    return 4;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex4 failed (step 1)\n");
	    return 4;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex4 failed (step 2)\n");
	    return 4;
	}
        if (!n1.AddNode("f1", E4_IOLAST, rank, n2)) {
            fprintf(stderr, "test vertex4 failed (step 6)\n");
            return 4;
        }
        if (!n2.IsValid()) {
            fprintf(stderr, "test vertex4 failed (step 7)\n");
            return 4;
        }
        if (n1.VertexCount() != 1) {
            fprintf(stderr, "test vertex4 failed (step 8)\n");
            return 4;
        }
        if (!n1.GetVertexRefByRank(1, f)) {
            fprintf(stderr, "test vertex4 failed (step 9)\n");
            return 4;
        }
        if (!f.IsValid()) {
            fprintf(stderr, "test vertex4 failed (step 10)\n");
            return 4;
        }
        if (!f.Get(n3)) {
            fprintf(stderr, "test vertex4 failed (step 11)\n");
            return 4;
        }
        if (!n3.IsValid()) {
            fprintf(stderr, "test vertex4 failed (step 12)\n");
            return 4;
        }
        if (n2 != n3) {
            fprintf(stderr, "test vertex4 failed (step 13)\n");
            return 4;
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex4 failed (step 13)\n");
	    return 4;
	}
    }

    return 0;
}

static int
test_vertex5()
{
    e4_Node n1, n2, n3;
    e4_Vertex f;
    int rank = 0;

    /*
     * Test e4_Vertex::SetNode.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex5 failed (step 0)\n");
	    return 5;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex5 failed (step 1)\n");
	    return 5;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex5 failed (step 2)\n");
	    return 5;
	}
        if (!n1.AddVertexRef("f1", E4_IOLAST, rank, 23, f)) {
            fprintf(stderr, "test vertex5 failed (step 6)\n");
            return 5;
        }
        if (!f.IsValid()) {
            fprintf(stderr, "test vertex5 failed (step 7)\n");
            return 5;
        }
        if (!f.SetNode(n2)) {
            fprintf(stderr, "test vertex5 failed (step 8)\n");
            return 5;
        }
        if (!n2.IsValid()) {
            fprintf(stderr, "test vertex5 failed (step 9)\n");
            return 5;
        }
        if (n1.VertexCount() != 1) {
            fprintf(stderr, "test vertex5 failed (step 10)\n");
            return 5;
        }
        if (!n1.GetVertexByRank(1, n3)) {
            fprintf(stderr, "test vertex5 failed (step 11)\n");
            return 5;
        }
        if (!n3.IsValid()) {
            fprintf(stderr, "test vertex5 failed (step 12)\n");
            return 5;
        }
        if (n2 != n3) {
            fprintf(stderr, "test vertex5 failed (step 13)\n");
            return 5;
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex5 failed (step 14)\n");
	    return 5;
	}
    }

    return 0;
}

static int
test_vertex6()
{
    e4_Node n1;
    e4_Vertex f;
    int rank = 0, i = 0;

    /*
     * Test e4_Vertex::Detach.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex6 failed (step 0)\n");
	    return 6;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex6 failed (step 1)\n");
	    return 6;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex6 failed (step 2)\n");
	    return 6;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n1.AddVertex("f1", E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex6 failed (step 6.1.%d)\n", i);
                return 6;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex6 failed (step 6.2.%d)\n", i);
                return 6;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex6 failed (step 6.3.%d)\n", i);
                return 6;
            }
        }
        if (!n1.GetVertexRefByRank(23, f)) {
            fprintf(stderr, "test vertex6 failed (step 7)\n");
            return 6;
        }
        if (!f.IsValid()) {
            fprintf(stderr, "test vertex6 failed (step 8)\n");
            return 6;
        }
        if (!f.Detach()) {
            fprintf(stderr, "test vertex6 failed (step 9)\n");
            return 6;
        }
        if (!n1.IsValid()) {
            fprintf(stderr, "test vertex6 failed (step 10)\n");
            return 6;
        }
        if (n1.VertexCount() != VF_VERTEXLIMIT - 1) {
            fprintf(stderr, "test vertex6 failed (step 11), %d %d\n",
		    VF_VERTEXLIMIT - 1, n1.VertexCount());
            return 6;
        }
        if (!f.IsValid()) {
            fprintf(stderr, "test vertex6 failed (step 12)\n");
            return 6;
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex6 failed (step 13)\n");
	    return 6;
	}
    }

    return 0;
}

static int
test_vertex7()
{
    e4_Node n1, n2;
    e4_Vertex f1, f2;
    int rank = 0, i = 0;

    /*
     * Test e4_Vertex::Detach with nested nodes.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex7 failed (step 0)\n");
	    return 7;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex7 failed (step 1)\n");
	    return 7;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex7 failed (step 2)\n");
	    return 7;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n1.AddVertex("f1", E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex7 failed (step 6.1.%d)\n", i);
                return 7;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex7 failed (step 6.2.%d)\n", i);
                return 7;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex7 failed (step 6.3.%d)\n", i);
                return 7;
            }
        }
        if (!n1.GetVertexRefByRank(23, f1)) {
            fprintf(stderr, "test vertex7 failed (step 7)\n");
            return 7;
        }
        if (!f1.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 8)\n");
            return 7;
        }
        if (!f1.SetNode(n2)) {
            fprintf(stderr, "test vertex7 failed (step 9)\n");
            return 7;
        }
        if (!n2.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 10)\n");
            return 7;
        }
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n2.AddVertex("f1", E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex7 failed (step 11.1.%d)\n", i);
                return 7;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex7 failed (step 11.2.%d)\n", i);
                return 7;
            }
            if (n2.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex7 failed (step 11.3.%d)\n", i);
                return 7;
            }
        }
        if (!n2.GetVertexRefByRank(23, f2)) {
            fprintf(stderr, "test vertex7 failed (step 12)\n");
            return 7;
        }
        if (!f2.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 13)\n");
            return 7;
        }
        if (!f1.Detach() || !f1.IsValid() || !f1.IsDetached()) {
            fprintf(stderr, "test vertex7 failed (step 14)\n");
            return 7;
        }
        if (!n1.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 15)\n");
            return 7;
        }
        if (n1.VertexCount() != VF_VERTEXLIMIT - 1) {
            fprintf(stderr, "test vertex7 failed (step 16)\n");
            return 7;
        }
        if (!f1.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 17)\n");
            return 7;
        }
        if (!n2.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 18)\n");
            return 7;
        }
        if (!f2.IsValid()) {
            fprintf(stderr, "test vertex7 failed (step 19)\n");
            return 7;
        }
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex7 failed (step 20)\n");
	    return 7;
	}
    }
    {
	e4_Storage s("foo.db", E4_METAKIT);

	s.Delete();
    }

    return 0;
}

static int
test_vertex8()
{
    e4_Node n1;
    e4_Vertex f1;
    int rank = 0, i = 0, j = 0, k = 0, nbytes = 0;
    char buf[32];
    double ff = 0.0;
    const char *ss;
    const void *bytes;
    const char *fnm;

    /*
     * Test e4_Vertex::Type and e4_Vertex::Name.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex8 failed (step 0)\n");
	    return 8;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex8 failed (step 1)\n");
	    return 8;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex8 failed (step 2)\n");
	    return 8;
	}
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    sprintf(buf, "f%d", i);
            j = i % (int) E4_VTLASTVERTEXTYPE;
            switch ((e4_VertexType) j) {
            case E4_VTNODE:
            case E4_VTINT:
                if (!n1.AddVertex(buf, E4_IOLAST, rank, i)) {
                    fprintf(stderr, "test vertex8 failed (step 6.1.%d)\n", i);
                    return 8;
                }
                break;
            case E4_VTDOUBLE:
                if (!n1.AddVertex(buf, E4_IOLAST, rank, (double) 3.145678)) {
                    fprintf(stderr, "test vertex8 failed (step 6.1.%d)\n", i);
                    return 8;
                }
                break;
            case E4_VTSTRING:
                if (!n1.AddVertex(buf, E4_IOLAST, rank, "hello there")) {
                    fprintf(stderr, "test vertex8 failed (step 6.1.%d)\n", i);
                    return 8;
                }
                break;
            case E4_VTBINARY:
                if (!n1.AddVertex(buf, E4_IOLAST, rank,
                                (const void *) "hello there", 12)) {
                    fprintf(stderr, "test vertex8 failed (step 6.1.%d)\n", i);
                    return 8;
                }
                break;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    sprintf(buf, "f%d", i);
            j = i % (int) E4_VTLASTVERTEXTYPE;
	    if (j == (int) E4_VTNODE) {
		j = (int) E4_VTINT;
	    }
	    if (!n1.GetVertexRefByRank(i + 1, f1)) {
	        fprintf(stderr, "test vertex8 failed (step 7.1.%d)\n", i);
		return 8;
	    }
	    if (!f1.IsValid()) {
		fprintf(stderr, "test vertex8 failed (step 7.2.%d)\n", i);
		return 8;
	    }
	    fnm = f1.Name();
	    if (fnm == NULL) {
		fprintf(stderr, "test vertex8 failed (step 7.3.%d)\n", i);
		return 8;
	    }
	    if (strcmp(fnm, buf) != 0) {
		fprintf(stderr, "test vertex8 failed (step 7.4.%d)\n", i);
		return 8;
	    }
            switch ((e4_VertexType) j) {
            case E4_VTINT:
		if (f1.Type() != E4_VTINT) {
		    fprintf(stderr, "test vertex8 failed (step 7.5.%d)\n", i);
		    return 8;
		}
	        if (!f1.Get(k)) {
		    fprintf(stderr, "test vertex8 failed (step 7.6.%d)\n", i);
		    return 8;
		}
		if (k != i) {
		    fprintf(stderr, "test vertex8 failed (step 7.7.%d)\n", i);
		    return 8;
		}
		break;
            case E4_VTDOUBLE:
	        if (f1.Type() != E4_VTDOUBLE) {
		    fprintf(stderr, "test vertex8 failed (step 7.5.%d)\n", i);
		    return 8;
		}
	        if (!f1.Get(ff)) {
		    fprintf(stderr, "test vertex8 failed (step 7.6.%d)\n", i);
		    return 8;
		}
                break;
            case E4_VTSTRING:
		if (f1.Type() != E4_VTSTRING) {
		    fprintf(stderr, "test vertex8 failed (step 7.5.%d)\n", i);
		    return 8;
		}
		if (!f1.Get(ss)) {
		    fprintf(stderr, "test vertex8 failed (step 7.6.%d)\n", i);
		    return 8;
		}
	        if (strcmp(ss, "hello there") != 0) {
		    fprintf(stderr, "test vertex8 failed (step 7.7.%d)\n", i);
		    return 8;
		}
                break;
            case E4_VTBINARY:
		if (f1.Type() != E4_VTBINARY) {
		    fprintf(stderr, "test vertex8 failed (step 7.5.%d)\n", i);
		    return 8;
		}
	        if (!f1.Get(bytes, nbytes)) {
		    fprintf(stderr, "test vertex8 failed (step 7.6.%d)\n", i);
		    return 8;
		}
	        if ((strcmp((char *) bytes, "hello there") != 0) ||
		    (nbytes != 12)) {
		    fprintf(stderr, "test vertex8 failed (step 7.7.%d)\n", i);
		    return 8;
		}
                break;
            }
        }
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex8 failed (step 8)\n");
	    return 8;
	}
    }

    return 0;
}

static int
test_vertex9()
{
    e4_Node n1;
    e4_Vertex f;
    int rank = 0, i = 0;
    char buf[32];
    const char *fnm;

    /*
     * Test e4_Vertex::Detach.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex9 failed (step 0)\n");
	    return 9;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex9 failed (step 1)\n");
	    return 9;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex9 failed (step 2)\n");
	    return 9;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    sprintf(buf, "f%d", i);
            if (!n1.AddVertex(buf, E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex9 failed (step 6.1.%d)\n", i);
                return 9;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex9 failed (step 6.2.%d)\n", i);
                return 9;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex9 failed (step 6.3.%d)\n", i);
                return 9;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    sprintf(buf, "f%d", i);
	    if (!n1.GetVertexRefByRank(i + 1, f)) {
		fprintf(stderr, "test vertex9 failed (step 7.1.%d)\n", i);
		return 9;
	    }
	    if (!f.IsValid()) {
		fprintf(stderr, "test vertex9 failed (step 7.2.%d)\n", i);
		return 9;
	    }
	    fnm = f.Name();
	    if (strcmp(fnm, buf) != 0) {
		fprintf(stderr, "test vertex9 failed (step 7.3.%d)\n", i);
		return 9;
	    }
	    sprintf(buf, "g%d", i);
	    if (!f.Rename(buf)) {
		fprintf(stderr, "test vertex9 failed (step 7.4.%d)\n", i);
		return 9;
	    }
	    fnm = n1.VertexName(i + 1);
	    if (strcmp(buf, fnm) != 0) {
		fprintf(stderr, "test vertex9 failed (step 7.5.%d)\n", i);
		return 9;
	    }
	    fnm = f.Name();
	    if (strcmp(fnm, buf) != 0) {
		fprintf(stderr, "test vertex9 failed (step 7.6.%d)\n", i);
		return 9;
	    }
	}
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex9 failed (step 8)\n");
	    return 9;
	}
    }

    return 0;
}

static int
test_vertex10()
{
    e4_Storage s1;
    e4_Node n1, n2;
    e4_Vertex f1;
    int i = 0, rank = 0;

    /*
     * Test e4_Vertex::GetNode and e4_Vertex::GetStorage.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex10 failed (step 0)\n");
	    return 10;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex10 failed (step 1)\n");
	    return 10;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex10 failed (step 2)\n");
	    return 10;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n1.AddVertex("f1", E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex10 failed (step 6.1.%d)\n", i);
                return 10;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex10 failed (step 6.2.%d)\n", i);
                return 10;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex10 failed (step 6.3.%d)\n", i);
                return 10;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    if (!n1.GetVertexRefByRank(i + 1, f1)) {
		fprintf(stderr, "test vertex10 failed (step 7.1.%d)\n", i);
		return 10;
	    }
	    if (!f1.IsValid()) {
		fprintf(stderr, "test vertex10 failed (step 7.2.%d)\n", i);
		return 10;
	    }
	    if (!f1.GetNode(n2)) {
		fprintf(stderr, "test vertex10 failed (step 7.3.%d)\n", i);
		return 10;
	    }
	    if (!n2.IsValid()) {
		fprintf(stderr, "test vertex10 failed (step 7.4.%d)\n", i);
		return 10;
	    }
	    if (n1 != n2) {
		fprintf(stderr, "test vertex10 failed (step 7.5.%d)\n", i);
		return 10;
	    }

	    /*
	     * Steps 7.6, 7.7 and 7.8 have been removed.
	     */

	    if (!f1.GetStorage(s1)) {
		fprintf(stderr, "test vertex10 failed (step 7.9.%d)\n", i);
		return 10;
	    }
	    if (!s1.IsValid()) {
		fprintf(stderr, "test vertex10 failed (step 7.10.%d)\n", i);
		return 10;
	    }
	    if (s != s1) {
		fprintf(stderr, "test vertex10 failed (step 7.11.%d)\n", i);
		return 10;
	    }
	}

	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex10 failed (step 8)\n");
	    return 10;
	}
    }

    return 0;
}

/*
 * Number of iterations to try.
 */

#define VF_STRESSITERATIONS	500000

static int
test_vertex11()
{
    e4_Storage s1;
    e4_Node n1;
    e4_Vertex f1, f2;
    int i = 0, k = 0, rank = 0;

    /*
     * Stress test:
     *
     * Use e4_Vertex::Get and e4_Vertex::Set to access a vertex many times.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex11 failed (step 0)\n");
	    return 11;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex11 failed (step 1)\n");
	    return 11;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex11 failed (step 2)\n");
	    return 11;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n1.AddVertex("f1", E4_IOLAST, rank, i)) {
                fprintf(stderr, "test vertex11 failed (step 6.1.%d)\n", i);
                return 11;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex11 failed (step 6.2.%d)\n", i);
                return 11;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex11 failed (step 6.3.%d)\n", i);
                return 11;
            }
        }
	if (!n1.GetVertexRefByRank(1, f1)) {
	    fprintf(stderr, "test vertex11 failed (step 7)\n", i);
	    return 11;
	}
	if (!f1.IsValid()) {
	    fprintf(stderr, "test vertex11 failed (step 8)\n", i);
	    return 11;
	}
	if (!n1.GetVertexRefByRank(2, f2)) {
	    fprintf(stderr, "test vertex11 failed (step 9)\n", i);
	    return 11;
	}
	if (!f2.IsValid()) {
	    fprintf(stderr, "test vertex11 failed (step 10)\n", i);
	    return 11;
	}
	for (i = 0; i < VF_STRESSITERATIONS; i++) {
	    if (!f1.Get(k)) {
		fprintf(stderr, "test vertex11 failed (step 11.1.%d)\n", i);
		return 11;
	    }
	    if (k != i) {
		fprintf(stderr, "test vertex11 failed (step 11.2.%d)\n", i);
		return 11;
	    }
	    if (!f1.Set(k + 1)) {
		fprintf(stderr, "test vertex11 failed (step 11.3.%d)\n", i);
		return 11;
	    }
	    if (!f1.Get(k)) {
		fprintf(stderr, "test vertex11 failed (step 11.4.%d)\n", i);
		return 11;
	    }
	    if (k != i + 1) {
		fprintf(stderr, "test vertex11 failed (step 11.5.%d)\n", i);
		return 11;
	    }
	    if (!f2.Get(k)) {
		fprintf(stderr, "test vertex11 failed (step 11.6.%d)\n", i);
		return 11;
	    }
	    if (k != i + 1) {
		fprintf(stderr, "test vertex11 failed (step 11.7.%d)\n", i);
		return 11;
	    }
	    if (!f2.Set(k + 1)) {
		fprintf(stderr, "test vertex11 failed (step 11.8.%d)\n", i);
		return 11;
	    }
	    if (!f2.Get(k)) {
		fprintf(stderr, "test vertex11 failed (step 11.9.%d)\n", i);
		return 11;
	    }
	    if (k != i + 2) {
		fprintf(stderr, "test vertex11 failed (step 11.10.%d)\n", i);
		return 11;
	    }
	}
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex11 failed (step 12)\n");
	    return 11;
	}
    }

    return 0;
}

static int
test_vertex12()
{
    e4_Storage s1;
    e4_Node n1, n2;
    e4_Vertex f1;
    int i = 0, rank = 0;

    /*
     * Test invalidVertex.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex12 failed (step 0)\n");
	    return 12;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex12 failed (step 1)\n");
	    return 12;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex12 failed (step 2)\n");
	    return 12;
	}
        for (i = 0; i < VF_VERTEXLIMIT; i++) {
            if (!n1.AddVertex("f1", E4_IOLAST, rank, 23)) {
                fprintf(stderr, "test vertex12 failed (step 6.1.%d)\n", i);
                return 12;
            }
            if (rank != i + 1) {
                fprintf(stderr, "test vertex12 failed (step 6.2.%d)\n", i);
                return 12;
            }
            if (n1.VertexCount() != i + 1) {
                fprintf(stderr, "test vertex12 failed (step 6.3.%d)\n", i);
                return 12;
            }
        }
	for (i = 0; i < VF_VERTEXLIMIT; i++) {
	    if (!n1.GetVertexRef("f1", i + 1, f1)) {
		fprintf(stderr, "test vertex12 failed (step 7.1.%d)\n", i);
		return 12;
	    }
	    if (!f1.IsValid()) {
		fprintf(stderr, "test vertex12 failed (step 7.2.%d)\n", i);
		return 12;
	    }
	    f1 = invalidVertex;
	    if (f1.IsValid()) {
		fprintf(stderr, "test vertex12 failed (step 7.3.%d)\n", i);
		return 12;
	    }
	}
	s.Delete();
	if (s.IsValid()) {
	    fprintf(stderr, "test vertex12 failed (step 8)\n");
	    return 12;
	}
    }

    return 0;
}

static int
test_vertex13()
{
    e4_Node n;
    e4_Vertex v;
    int i = 0, rank = 0;

    /*
     * This test checks that the storage for vertices is properly
     * recycled (as denoted by reuse of the unique IDs for vertices).
     * The test is specific to the E4_METAKIT driver because it
     * relies on the property of the driver of reusing unique IDs.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex13 failed (step 0)\n");
	    return 13;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex13 failed (step 1)\n");
	    return 13;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex13 failed (step 2)\n");
	    return 13;
	}
	if ((!n.AddVertexRef("v", E4_IOLAST, rank, 42, v)) ||
	    (!v.IsValid())) {
	    fprintf(stderr, "test vertex13 failed (step 5)\n");
	    return 13;
	}
	for (i = 0; i < 255; i++) {
	    if ((!v.Detach()) || (!v.IsValid())) {
		fprintf(stderr, "test vertex13 failed (step 6.1.%d)\n", i);
		return 13;
	    }
	    if ((!n.AddVertexRef("v", E4_IOLAST, rank, 42, v)) ||
		(!v.IsValid())) {
		fprintf(stderr, "test vertex13 failed (step 6.2.%d)\n", i);
		return 13;
	    }
	}
	s.Delete();
	if ((s.IsValid()) || (n.IsValid()) || (v.IsValid())) {
	    fprintf(stderr, "test vertex13 failed (step 7)\n");
	    return 13;
	}
    }

    return 0;
}

static int
test_vertex14()
{
    e4_Node n1, n2;
    e4_Vertex v;
    int rank = 0;

    /*
     * This test exercises v.Set(n).
     */


    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex14 failed (step 1)\n");
	    return 14;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex14 failed (step 1)\n");
	    return 14;
	}
	if (!s.GetRootNode(n1) || !n1.IsValid() || !n1.IsRoot()) {
	    fprintf(stderr, "test vertex14 failed (step 2)\n");
	    return 14;
	}
	if (!s.CreateDetachedNode(n2) || !n2.IsValid() || !n2.IsDetached()) {
	    fprintf(stderr, "test vertex14 failed (step 3)\n");
	    return 14;
	}
	if ((!n1.AddVertexRef("v", E4_IOLAST, rank, 42, v)) ||
	    (!v.IsValid())) {
	    fprintf(stderr, "test vertex14 failed (step 8)\n");
	    return 14;
	}
	if (!v.Set(n2)) {
	    fprintf(stderr, "test vertex14 failed (step 9)\n");
	    return 14;
	}
	
	s.Delete();
	if ((s.IsValid()) || (n1.IsValid()) ||
	    (n2.IsValid()) || (v.IsValid())) {
	    fprintf(stderr, "test vertex14 failed (step 10)\n");
	    return 14;
	}
    }

    return 0;
}

static int
test_vertex15()
{
    e4_Node n;
    e4_Vertex v;
    int vud = 0, rank = 0;

    /*
     * This test checks that user data attached to vertices is saved into
     * the persistent storage.
     */

    {
	e4_Storage s;

	if (!clean_storage("foo.db", s)) {
	    fprintf(stderr, "test vertex15 failed (step 0)\n");
	    return 15;
	}
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex15 failed (step 1)\n");
	    return 15;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex15 failed (step 2)\n");
	    return 15;
	}
	if (!s.IsStable() || !s.Commit() || !s.IsStable()) {
	    fprintf(stderr, "test vertex15 failed (step 2.1)\n");
	    return 15;
	}
	if ((!n.AddVertexRef("v", E4_IOLAST, rank, 42, v)) ||
	    (!v.IsValid())) {
	    fprintf(stderr, "test vertex15 failed (step 3.0)\n");
	    return 15;
	}
	if (s.IsStable()) {
	    fprintf(stderr, "test vertex15 failed (step 3.1)\n");
	    return 15;
	}
	if (!s.Commit()) {
	    fprintf(stderr, "test vertex15 failed (step 3.2)\n");
	    return 15;
	}
	if (!v.GetUserData(vud) || (vud != 0)) {
	    fprintf(stderr, "test vertex15 failed (step 4.0)\n");
	    return 15;
	}
	if (!s.IsStable()) {
	    fprintf(stderr, "test vertex15 failed (step 4.1)\n");
	    return 15;
	}
	if (!v.SetUserData(101)) {
	    fprintf(stderr, "test vertex15 failed (step 5.0)\n");
	    return 15;
	}
	if (!v.GetUserData(vud) || (vud != 101) || s.IsStable()) {
	    fprintf(stderr, "test vertex15 failed (step 5.1)\n");
	    return 15;
	}

	/*
	 * By going out of scope, the storage is committed and closed.
	 */
    }

    {
	e4_Storage s("foo.db", E4_METAKIT);
	if (!s.IsValid()) {
	    fprintf(stderr, "test vertex15 failed (step 6)\n");
	    return 15;
	}
	if (!s.GetRootNode(n) || !n.IsValid() || !n.IsRoot()) {
	    fprintf(stderr, "test vertex15 failed (step 7)\n");
	    return 15;
	}
	if (!n.GetVertexRef("v", v) || !v.IsValid()) {
	    fprintf(stderr, "test vertex15 failed (step 8)\n");
	    return 15;
	}
	if (!v.GetUserData(vud) || (vud != 101) || !s.IsStable()) {
	    fprintf(stderr, "test vertex15 failed (step 9)\n");
	    return 15;
	}

	s.Delete();
    }

    return 0;
}

int
test_vertex()
{
    int result = 0;

    fprintf(stderr, "Running e4_Vertex tests: ");

    result = test_vertex1();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex7();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex2();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex3();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex4();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex5();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex6();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex8();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex9();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex10();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex11();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex12();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex13();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex14();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_vertex15();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".\n");    
    return 0;
}
