/*
 *  test4600.fileop - 4600 series of the regress.cal test suite
 *
 * Copyright (C) 1999,2023  Ernest Bowen and Landon Curt Noll
 *
 * Primary author:  Ernest Bowen
 *
 * Calc is open software; you can redistribute it and/or modify it under
 * the terms of the version 2.1 of the GNU Lesser General Public License
 * as published by the Free Software Foundation.
 *
 * Calc is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
 * Public License for more details.
 *
 * A copy of version 2.1 of the GNU Lesser General Public License is
 * distributed with calc under the filename COPYING-LGPL.  You should have
 * received a copy with calc; if not, write to Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Under source code control:   1996/07/02 20:04:40
 * File existed as early as:    1996
 *
 * Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/
 */


defaultverbose = 1;     /* default verbose value */

/*
 * test globals
 */
global A, f, pos;

define stest(str, verbose)
{
        local x;

        /* setup */
        if (isnull(verbose))
                verbose = defaultverbose;
        if (verbose > 0) {
                print str:":",:;
        }
        x = rm("-f", "junk4600");

        /*
         * do file operations
         */
        f = fopen("junk4600", "wb");
        if (iserror(f)) {
                print 'failed';
                print '**** fopen("junk4600", "wb") failed';
                return 1;
        }
        if (iserror(fputs(f,
         "Fourscore and seven years ago our fathers brought forth\n",
         "on this continent a new nation, conceived in liberty and dedicated\n",
         "to the proposition that all men are created equal.\n"))) {
                print 'failed';
                print '**** fputs(f, "Fourscore ... failed';
                return 1;
        }
        if (iserror(freopen(f, "rb"))) {
                print 'failed';
                print '**** iserror(freopen(f, "rb")) failed';
                return 1;
        }
        if (iserror(rewind(f))) {
                print 'failed';
                print '**** iserror(rewind(f)) failed';
                return 1;
        }
        if (search(f, "and") != 10) {
                print 'failed';
                print '**** search(f, "and") != 10 failed';
                return 1;
        }
        if (ftell(f) != 13) {
                print 'failed';
                print '**** ftell(f) != 13 failed';
                return 1;
        }
        if (search(f, "and") != 109) {
                print 'failed';
                print '**** search(f, "and") != 109 failed';
                return 1;
        }
        if (ftell(f) != 112) {
                print 'failed';
                print '**** ftell(f) != 112 failed';
                return 1;
        }
        if (!isnull(search(f, "and"))) {
                print 'failed';
                print '**** !isnull(search(f, "and")) failed';
                return 1;
        }
        if (ftell(f) != 172) {
                print 'failed';
                print '**** ftell(f) != 172 failed';
                return 1;
        }
        if (rsearch(f, "and") != 109) {
                print 'failed';
                print '**** rsearch(f, "and") != 109 failed';
                return 1;
        }
        if (ftell(f) != 111) {
                print 'failed';
                print '**** ftell(f) != 111 failed';
                return 1;
        }
        if (iserror(fseek(f, -4, 1))) {
                print 'failed';
                print '**** iserror(fseek(f, -4, 1)) failed';
                return 1;
        }
        if (rsearch(f, "and") != 10) {
                print 'failed';
                print '**** rsearch(f, "and") != 10 failed';
                return 1;
        }
        if (ftell(f) != 12) {
                print 'failed';
                print '**** ftell(f) != 12 failed';
                return 1;
        }
        if (iserror(fseek(f, -4, 1))) {
                print 'failed';
                print '**** iserror(fseek(f, -4, 1)) failed';
                return 1;
        }
        if (!isnull(rsearch(f, "and"))) {
                print 'failed';
                print '**** !isnull(rsearch(f, "and")) failed';
                return 1;
        }
        if (ftell(f) != 0) {
                print 'failed';
                print '**** ftell(f) != 0 failed';
                return 1;
        }
        if (iserror(fclose(f))) {
                print 'failed';
                print '**** iserror(fclose(f)) failed';
                return 1;
        }

        /*
         * cleanup
         */
        x = rm("junk4600");
        if (verbose > 0) {
                printf("passed\n");
        }
        return 0;
}

define ttest(str, m, n, verbose)
{
        local a, s, i, j;

        if (isnull(verbose))
                verbose = defaultverbose;
        if (verbose > 0) {
                print str:":",:;
        }
        i = rm("-f", "junk4600");
        f = fopen("junk4600", "wb");

        if (isnull(n))
                n = 4;
        if (isnull(m))
                m = 4;

        mat A[m];
        mat pos[m + 1];

        pos[0] = 0;
        for (i = 0; i < m; i++) {
                j = 1 + randbit(n);
                a = "";
                while (j-- > 0)
                        a = strcat(a, char(rand(32, 127)));
                A[i] = a;
                fputs(f, a);
                pos[i+1] = ftell(f);
                if (verbose > 1)
                        printf("A[%d] has length %d\n", i, strlen(a));
        }
        fflush(f);
        if (verbose > 1)
                printf("File has size %d\n", pos[i]);
        freopen(f, "rb");
        if (size(f) != pos[i]) {
                print 'failed';
                printf("**** Failure 1 for file size\n");
                return 1;
        }
        for (i = 0; i < m; i++) {
                rewind(f);
                for (;;) {
                        j = search(f, A[i]);
                        if (isnull(j) || j > pos[i]) {
                                print 'failed';
                                printf("**** Failure 2 for i = %d\n", i);
                                return 1;
                        }
                        if (j == pos[i])
                                break;
                        fseek(f, j + 1, 0);

                }
                if (ftell(f) != pos[i + 1]) {
                        print 'failed';
                        printf("**** Failure 3 for i = %d\n", i);
                        return 1;
                }
        }
        for (i = m - 1; i >= 0; i--) {
                fseek(f, 0, 2);
                for (;;) {
                        j = rsearch(f, A[i]);
                        if (isnull(j) || j < pos[i]) {
                                print 'failed';
                                printf("**** Failure 4 for i = %d\n", i);
                                return 1;
                        }
                        if (j == pos[i])
                                break;
                        fseek(f, -1, 1);
                }
                if (ftell(f) != pos[i + 1] - 1) {
                        print 'failed';
                        printf("**** Failure 5 for i = %d\n", i);
                        return 1;
                }
        }
        if (iserror(fclose(f))) {
                print 'failed';
                printf("**** Failure 6 for i = %d\n", i);
                return 1;
        }
        i = rm("junk4600");
        if (verbose > 0) {
                printf("passed\n");
        }
        return 0;
}

define sprint(x)
{
        local i, n;

        n = strlen(x);
        for (i = 1; i <= n; i++) print ord(substr(x, i, 1)),;
        print;
}

define findline(f,s)
{

        if (!isfile(f))
                quit "First argument to be a file";
        if (!isstr(s))
                quit "Second argument to be a string";
        if (!isnull(search(f,s))) {
                rsearch(f, "\n");
                print fgetline(f);
        }
}

define findlineold(f,s)
{
        local str;

        if (!isfile(f))
                quit "First argument to be a file";
        if (!isstr(s))
                quit "Second argument to be a string";

        while (!isnull(str = fgetline(f)) && strpos(str, s) == 0);
                print str;
}

/*
 * test4600 - perform all of the above tests a bunch of times
 */
define test4600(v, tnum)
{
        local n;        /* test parameter */
        local i;

        /*
         * set test parameters
         */
        srand(4600e4600);

        /*
         * test a lot of stuff
         */
        for (i=0; i < 10; ++i) {
                err += ttest(strcat(str(tnum++),
                             ": ttest(",str(i),",",str(i),")"), i, i, v);
                err += stest(strcat(str(tnum++), ": stest()"), v);
        }

        /*
         * report results
         */
        if (v > 1) {
                if (err) {
                        print "****", err, "error(s) found in testall";
                } else {
                        print "no errors in testall";
                }
        }
        return tnum;
}
