/*
 * testrecount.cpp --
 *
 * Tests that ensure that reference counting is working properly.
 *
 * 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"

static int
test_refcount1()
{
    e4_Storage s;

    if (!clean_storage("foo.db", s)) {
	fprintf(stderr, "test refcount1 failed, step 0\n");
	return 1;
    }
    if (!s.IsValid()) {
	fprintf(stderr, "test refcount1 failed, step 1\n");
	return 1;
    }
    if (s.RefCount() != 1) {
	fprintf(stderr, "test refcount1 failed, step 2\n");
	return 1;
    }
    
    e4_Storage s1;

    if (s1.IsValid()) {
	fprintf(stderr, "test refcount1 failed, step 3\n");
	return 1;
    }

    s1 = s;

    if (!s1.IsValid()) {
	fprintf(stderr, "test refcount1 failed, step 4\n");
	return 1;
    }
    if ((s.RefCount() != 2) || (s1.RefCount() != 2)) {
	fprintf(stderr, "test refcount1 failed, step 5\n");
	return 1;
    }
    if ((s != s1) || (s1 != s)) {
	fprintf(stderr, "test refcount1 failed, step 6\n");
	return 1;
    }

    s.Delete();

    if (s.IsValid() || s1.IsValid()) {
	fprintf(stderr, "test refcount1 failed, step 7\n");
	return 1;
    }
    if ((s1.RefCount() != 1) || (s.RefCount() != -1)) {
	fprintf(stderr, "test refcount1 failed, step 8\n");
	return 1;
    }
    if ((s1 != s) || (s != s1) || (s != invalidStorage) ||
	(s1 != invalidStorage)) {
	fprintf(stderr, "test refcount1 failed, step 9\n");
	return 1;
    }

    s1.Delete();

    if (s.IsValid() || s1.IsValid()) {
	fprintf(stderr, "test refcount1 failed, step 10\n");
	return 1;
    }
    if ((s1.RefCount() != -1) || (s.RefCount() != -1)) {
	fprintf(stderr, "test refcount1 failed, step 11\n");
	return 1;
    }
    if ((s1 != s) || (s1 != s)) {
	fprintf(stderr, "test refcount1 failed, step 12\n");
	return 1;
    }

    return 0;
}

static int
test_refcount2()
{
    e4_Storage s1, s2, s3;

    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount2 failed, step 1\n");
	return 2;
    }
    s1 = s2;
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount2 failed, step 2\n");
	return 2;
    }

    return 0;
}

static int
test_refcount3()
{
    e4_Storage s1, s2, s3;

    if ((s1 != s2) || (s1 != s3)) {
	fprintf(stderr, "test refcount3 failed, step 1\n");
	return 3;
    }
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 2\n");
	return 3;
    }
    s1 = s2;
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 3\n");
	return 3;
    }
    
    e4_Storage o;

    if (!clean_storage("foo.db", o)) {
	fprintf(stderr, "test refcount3 failed, step 4.0\n");
	return 3;
    }
    if ((!o.IsValid()) || (o.RefCount() != 1)) {
	fprintf(stderr, "test refcount3 failed, step 4\n");
	return 3;
    }
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 5\n");
	return 3;
    }
    s1 = o;
    if ((o.RefCount() != 2) || (s1.RefCount() != 2) ||
	(s2.RefCount() != -1) || (s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 6\n");
	return 3;
    }
    s2 = s1;
    if ((o.RefCount() != 3) || (s1.RefCount() != 3) ||
	(s2.RefCount() != 3) || (s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 7\n");
	return 3;
    }
    s3 = s2;
    if ((o.RefCount() != 4) || (s1.RefCount() != 4) ||
	(s2.RefCount() != 4) || (s3.RefCount() != 4)) {
	fprintf(stderr, "test refcount3 failed, step 8\n");
	return 3;
    }
    if ((o != s1) || (o != s2) || (o != s3)) {
	fprintf(stderr, "test refcount3 failed, step 9\n");
	return 3;
    }
    o = invalidStorage;
    if ((o.RefCount() != -1) || (s1.RefCount() != 3) ||
	(s2.RefCount() != 3) || (s3.RefCount() != 3)) {
	fprintf(stderr, "test refcount3 failed, step 10\n");
	return 3;
    }
    s1 = invalidStorage;
    if ((o.RefCount() != -1) || (s1.RefCount() != -1) ||
	(s2.RefCount() != 2) || (s3.RefCount() != 2)) {
	fprintf(stderr, "test refcount3 failed, step 11\n");
	return 3;
    }
    s2 = invalidStorage;
    if ((o.RefCount() != -1) || (s1.RefCount() != -1) ||
	(s2.RefCount() != -1) || (s3.RefCount() != 1)) {
	fprintf(stderr, "test refcount3 failed, step 12\n");
	return 3;
    }
    s3.Delete();
    if ((o.RefCount() != -1) || (s1.RefCount() != -1) ||
	(s2.RefCount() != -1) || (s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount3 failed, step 13\n");
	return 3;
    }

    return 0;
}

static int
test_refcount4()
{
    e4_Storage s1, s2, s3;

    if ((s1 != s2) || (s1 != s3)) {
	fprintf(stderr, "test refcount4 failed, step 1\n");
	return 4;
    }
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount4 failed, step 2\n");
	return 4;
    }
    s1 = s2;
    if ((s1.RefCount() != -1) || (s2.RefCount() != -1) || 
	(s3.RefCount() != -1)) {
	fprintf(stderr, "test refcount4 failed, step 3\n");
	return 4;
    }
    
    e4_Storage o1("foo.db", E4_METAKIT);
    e4_Storage o2("foo.db", E4_METAKIT);

    if ((!o1.IsValid()) || (!o2.IsValid()) || (o1 != o2) ||
	(o1.RefCount() != 2) || (o2.RefCount() != 2)) {
	fprintf(stderr, "test refcount4 failed, step 4\n");
	return 4;
    }

    s1 = o1;
    s2 = o2;

    if ((o1.RefCount() != 4) || (s1.RefCount() != 4) ||
	(o2.RefCount() != 4) || (s2.RefCount() != 4) ||
	(s3.RefCount() != -1) || (s1 != s2)) {
	fprintf(stderr, "test refcount4 failed, step 5\n");
	return 4;
    }

    o1.Delete();

    if (o1.IsValid() || o2.IsValid() || s1.IsValid() || s2.IsValid()) {
	fprintf(stderr, "test refcount4 failed, step 6\n");
	return 4;
    }
    if ((o1.RefCount() != -1) || (s1.RefCount() != 3) ||
	(o2.RefCount() != 3) || (s2.RefCount() != 3) ||
	(s3.RefCount() != -1) || (s1 != s2)) {
	fprintf(stderr, "test refcount4 failed, step 7\n");
	return 4;
    }

    return 0;
}
    
int
test_refcount()
{
    int result = 0;

    fprintf(stderr, "Running e4_Refcount tests: ");
    result = test_refcount1();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_refcount2();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_refcount3();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".");
    result = test_refcount4();
    if (result != 0) {
	return result;
    }
    fprintf(stderr, ".\n");
    
    return 0;
}
