//-*-c++-*--------------------------------------------------------------
//  extTest.cpp
//   Simple test of PhysExtents and LogExtents.
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfAncil/ssTest/extTest.cpp,v $
// $Revision: 1.21 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/04/30 23:31:37 $
//

#include "nsrLib.h"
#include <stdio.h>
#include <stdlib.h>
#include "nsrRSSdv.h"

INT32
main (INT16 argc, CHAR_PTR argv[])
{
    Error err;
    extern int      optind;     // For getopt()
    extern CHAR_PTR optarg;     // For getopt()
    UINT32          c;
    String          str("tbox"); // Default

    while((c = getopt(argc,argv,"f:")) != EOF) {
        switch(c)
        {
        case 'f':
            str = optarg;
            break;
        default:
            printf("Usage:  %s [-f devfile]\n",argv[0]);
            break;
        }
    }
    
// Compare it with the items returned/referenced by the brackets
// operator.

    DriveDevice    ddev(str);
    if ( err = ddev.error() ) {
        fprintf( stderr,"Drive Device Construction error: %s\n",
                 err.message() );
        return -1;
    }
    
    PhysicalVolume pv(&ddev);
    if ( err = pv.error() ) {
        fprintf( stderr,"PhysicalVolume Construction error: %s\n",
                 err.message() );
        return -2;
    }
    
    PhysExtent     pe(&pv,0,0);
    if ( err = pe.error() ) {
        fprintf( stderr,"PhysExtent Construction error: %s\n",
                 err.message() );
        return -3;
    }
    
    PhysExtentList pel;
    if ( err = pel.error() ) {
        fprintf( stderr,"PhysExtentList Construction error: %s\n",
                 err.message() );
        return -4;
    }
    
    UINT32 i;

    printf("Building 100-entry PhysExtentList...\n");
    for (i = 0; i<100; i++) {
        pe.reinit(pe.physVolumep(),i,100-i,err);
        if ( err ) {
            fprintf( stderr,"PhysExtentList.reinit(%ld,%ld) error: %s\n",
                     i,100-i,err.message() );
            return -20;
        }
        // pe.startSector(i);
        // pe.numSectors(100-i);
        pel.append(pe,err);
        if ( err ) {
            fprintf( stderr,"PhysExtentList.append() error: %s\n",err.message() );
            return -5;
        }
    }

    const PhysExtent * pep;
    UINT16             mismatches = 0;

    printf("Comparing PhysExtents using at()...\n");
    for (i = 0; i<100; i++) {
        pep = pel.at(i,err);
        if ( err ) {
            fprintf( stderr,"PhysExtentList.at() error: %s\n",err.message() );
            return -6;
        }
        if (i != pep->startSector()) {
            fprintf(stderr," Sector Mismatch: pel[%ld].sect == %ld\n",
                    i,pep->startSector());
            mismatches ++;
        }
        if ((100-i) != pep->numSectors()) {
            fprintf(stderr," Sector Mismatch: pel[%ld].ns == %ld\n",
                    i,pep->numSectors());
            mismatches ++;
        }
    }
    if ( mismatches != 0 ) {
        fprintf(stderr,"Test Aborted with %ld mismatches.\n",mismatches);
        return -7;
    }

    PhysExtentListIter peli(pel);

    printf("Comparing PhysExtents using iterator...\n");
    for (i=0,peli.reset(); peli.next();i++) {
        pep = peli.key();
        if (i != pep->startSector()) {
            fprintf(stderr," Sector Mismatch: pel[%ld].sect == %ld\n",
                    i,pep->startSector());
            mismatches ++;
        }
        if ((100-i) != pep->numSectors()) {
            fprintf(stderr," Sector Mismatch: pel[%ld].ns == %ld\n",
                    i,pep->numSectors());
            mismatches ++;
        }
    }
    if ( mismatches != 0 ) {
        fprintf(stderr,"Test Aborted with %ld mismatches.\n",mismatches);
        return -8;
    }

    printf("Done with PhysExtents.\n");

// LogExtent testing:

    const UINT32 PartitionBegin  = 257;  // Maestro I (by pure coincidence)
    const UINT32 PartitionLength = 1000; // arbitrary

    const UINT32 ImaginaryExtLength = 0x12345678; // arbitrary

    const UINT32 TestExtentStart    = 49;         // arbitrary
    const UINT32 TestExtentBlocks   = 283;        // arbitrary

    pe.reinit(pe.physVolumep(),PartitionBegin,PartitionLength,err);
    if ( err ) {
        fprintf(stderr,"Error reinitializing PE(pBegin,pLen): %s\n",
                err.message());
        return -20;
    }
        
    
    Partition     part (pe);
    LogicalVolume lv   (&part);

    LongAllocDesc  lad;
    ShortAllocDesc sad;

    printf("Testing LogExtent fromAD() method ... ");
    
    const UINT32 TestBlockMultLen = TestExtentBlocks * part.blockSize();
    const UINT32 TestExtentLen    = TestBlockMultLen - 511;

    LogExtent adle(&part,0,0);
    err = adle.error();
    if ( err ) {
        fprintf(stderr,"\n LogExtent construction error: %s\n",
               err.message());
        return -20;
    }

    lad.partRefNo(0);
    lad.logBlockNo(TestExtentStart);
    lad.extLength(TestExtentLen);
    lad.extType(ext_Recorded);

    // OLD: adle.fromLongAD(&lv,lad,err);
    lad.toLogExtent(&lv,adle,err);

    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD() error: %s\n",
               err.message());
        return -20;
    }
    if ( adle.infoLen() != TestExtentLen ) {
        fprintf(stderr,"\n LogExtent infoLen() mismatch (%ld != %ld)\n",
               adle.infoLen(),TestExtentLen );
        return -20;
    }
    if ( adle.blockMultLen() != TestBlockMultLen ) {
        fprintf(stderr,"\n LogExtent blockMultLen() mismatch (%ld != %ld)\n",
               adle.blockMultLen(),TestBlockMultLen );
        return -20;
    }
    if ( adle.extentType() != Recorded ) {
        fprintf(stderr,"\n LogExtent extentType() not `Recorded' (%ld)\n",
               adle.extentType() );
        return -20;
    }

    lad.extType(ext_Allocated);    // defaults to unerased?
    // OLD:  adle.fromLongAD(&lv,lad,err);
    lad.toLogExtent(&lv,adle,err);

    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(unerased) error: %s\n",
               err.message());
        return -20;
    }
    if ( adle.extentType() != Unerased ) {
        fprintf(stderr,"\n LogExtent extentType() not `Unerased' (%ld)\n",
               (UINT32)adle.extentType() );
        return -20;
    }

    lad.markErased();
    // OLD:  adle.fromLongAD(&lv,lad,err);
    lad.toLogExtent(&lv, adle, err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(erased) error: %s\n",
               err.message());
        return -20;
    }

    if ( adle.extentType() != Erased ) {
        fprintf(stderr,"\n LogExtent extentType() not `Erased' (%ld)\n",
               (UINT32)adle.extentType() );
        return -20;
    }

    // NEEDS TEST FOR ext_AllocExtent

    printf("Done.\n");
    printf("Testing LogicalVolume and Partition methods in LogExtent ... ");

    if ( adle.partitionp() != &part ) {
        fprintf(stderr,"\n Partition pointer in extent is incorrect: ( %p != %p )\n",
               adle.partitionp(),&part );
        return -20;
    }
    
    if ( adle.logVolumep() != &lv ) {
        fprintf(stderr,"\n LogicalVolume pointer in extent is incorrect: ( %p != %p )\n",
                adle.logVolumep(),&lv );
        return -20;
    }

    printf("Done.\n");
    printf("Testing imaginary extents ... ");

    LogExtent     imle(&part,ImaginaryExtLength);
    err = imle.error();
    if ( err ) {
        fprintf(stderr,"\n LogExtent construction(imaginary) error: %s\n",
               err.message());
        return -20;
    }

    if ( imle.infoLen() != ImaginaryExtLength ) {
        fprintf(stderr,"\n(PRE)Imaginary LogExtent length mismatch: 0x%lx != 0x%lx\n",
               imle.infoLen(),ImaginaryExtLength);
        return -20;
    }
    if ( imle.extentType() != Imaginary ) {
        fprintf(stderr,"\n(PRE)Imaginary LogExtent wrong type: %ld\n",(UINT32)imle.extentType());
        return -20;
    }

#ifdef AD_VERIFY

    imle.toLongAD(lad);
    imle.fromLongAD(&lv,lad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if ( imle.infoLen() != ImaginaryExtLength ) {
        fprintf(stderr,"\n(LAD)Imaginary LogExtent length mismatch: 0x%lx != 0x%lx\n",
               imle.infoLen(),ImaginaryExtLength);
        return -20;
    }
    if ( imle.extentType() != Imaginary ) {
        fprintf(stderr,"\n(LAD)Imaginary LogExtent wrong type: %ld\n",(UINT32)imle.extentType());
        return -20;
    }

    imle.toShortAD(sad);
    imle.fromShortAD(&part,sad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromShortAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if ( imle.infoLen() != ImaginaryExtLength ) {
        fprintf(stderr,"\n(SAD)Imaginary LogExtent length mismatch: 0x%lx != 0x%lx\n",
               imle.infoLen(),ImaginaryExtLength);
        return -20;
    }
    if ( imle.extentType() != Imaginary ) {
        fprintf(stderr,"\n(SAD)Imaginary LogExtent wrong type: %ld\n",(UINT32)imle.extentType());
        return -20;
    }

#endif

    printf("Done.\n");
    printf("Testing LogExtent out of bounds errors ... ");

    LogExtent     le(&part,0,0);
    if ( err ) {
        fprintf(stderr,"\n LogExtent construction error: %s\n",
               err.message());
        return -20;
    }

    le.reinit(le.partitionp(),le.startBlock(),
              (PartitionLength+1) * le.blockSize(),err);  // Beyond Maximum Length
    if ( err != NSR::error_LE_beyond_partition ) {
        printf ("LogExtent (len=max+1) had wrong error: %s\n",
                err.message());
        return -20;
        }

    le.reinit(le.partitionp(),le.startBlock(),
              PartitionLength * le.blockSize(),err);  // Maximum Length
    if ( err ) {
        printf ("LogExtent reinit(st=0;len=max) had error: %s\n",
                err.message());
        return -20;
    }

    le.reinit(le.partitionp(),1,
              le.infoLen(),err);  // Should exceed end
    if ( err != NSR::error_LE_beyond_partition ) {
        printf ("LogExtent (st=1;len=max) had wrong error: %s\n",
                err.message());
        return -20;
    }
    
    le.reinit(le.partitionp(),
              TestExtentStart,
              TestExtentBlocks * le.blockSize(),err);
    if ( err ) {
        fprintf(stderr,"\nLogExtent had error when set to max length: %s\n",
                err.message());
        return -20;
    }
    
    printf("Done.\n");
    printf("Testing LogExtent infoLen() limitations ... ");

    UINT32 TooShortLen = le.blockMultLen() - part.blockSize();
    UINT32 MinimumLen  = TooShortLen + 1;
    UINT32 TooLongLen  = le.blockMultLen() + 1;
    
    le.infoLen(TooShortLen,err);
    if ( err != NSR::error_InfoLen_illegal ) {
        fprintf(stderr,"\n LogExtent infoLen(short) wrong error: %s\n",
                err.message());
        return -20;
    }

    le.infoLen(TooLongLen,err);
    if ( err != NSR::error_InfoLen_illegal ) {
        fprintf(stderr,"\n LogExtent infoLen(long) wrong error: %s\n",
                err.message());
        return -20;
    }
    for (UINT32 tstLen = MinimumLen; tstLen < TooLongLen; tstLen++) {
        le.infoLen(tstLen,err);
        if ( err ) {
            fprintf(stderr,"\n LogExtent infoLen(%ld) error: %s\n",
                    tstLen,err.message());
            return -20;
        }
        if ( le.infoLen() != tstLen ) {
            fprintf(stderr,"\nLogExtent infoLen() error: (%ld != %ld)\n",
                   le.infoLen(),tstLen );
            return -20;
        }
    }

    printf("Done.\n");
    printf("Testing LogExtent extentType methods ... ");

    le.markErased();
    if (le.extentType() != Erased )
        fprintf(stderr,"\n(PRE)LogExtent Unsuccessful setting type to Erased (%ld).\n",
               (UINT32)le.extentType());

#ifdef AD_VERIFY

    le.toLongAD(lad);
    le.fromLongAD(&lv,lad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Erased ) {
        fprintf(stderr,"\n(LAD)LogExtent Unsuccessful setting type to Erased (%ld).\n",
                (UINT32)le.extentType());
        return -20;
    }

    le.toShortAD(sad);
    le.fromShortAD(&part,sad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromShortAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Erased ) {
        fprintf(stderr,"\n(SAD)LogExtent Unsuccessful setting type to Erased (%ld).\n",
                (UINT32)le.extentType());
        return -20;
    }

#endif

    le.markRecorded();
    if (le.extentType() != Recorded ) {
        fprintf(stderr,"\n(PRE)LogExtent Type not Recorded (%ld).\n",
                (UINT32)le.extentType());
        return -20;
    }

#ifdef AD_VERIFY

    le.toLongAD(lad);
    le.fromLongAD(&lv,lad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Recorded ) {
        fprintf(stderr,"\n(LAD)LogExtent Type not Recorded (%ld).\n",
               (UINT32)le.extentType());
        return -20;
    }

    le.toShortAD(sad);
    le.fromShortAD(&part,sad);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromShortAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Recorded ) {
        fprintf(stderr,"\n(SAD)LogExtent Type not Recorded (%ld).\n",
               (UINT32)le.extentType());
        return -20;
    }

#endif

    le.markUnerased();
    if (le.extentType() != Unerased ) {
        fprintf(stderr,"\n(PRE)LogExtent Type not Unerased (%ld).\n",
               (UINT32)le.extentType());
        return -20;
    }

#ifdef AD_VERIFY

    le.toLongAD(lad);
    le.fromLongAD(&lv,lad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromLongAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Unerased ) {
        fprintf(stderr,"\n(LAD)LogExtent Type not Unerased (%ld).\n",
               (UINT32)le.extentType());
        return -20;
    }
    
    le.toShortAD(sad);
    le.fromShortAD(&part,sad,err);
    if ( err ) {
        fprintf(stderr,"\n LogExtent fromShortAD(VERIFY) error: %s\n",
               err.message());
        return -20;
    }

    if (le.extentType() != Unerased ) {
        fprintf(stderr,"\n(SAD)LogExtent Type not Unerased (%ld).\n",
               (UINT32)le.extentType());
        return -20;
    }

#endif

    printf("Done.\n");
    printf("Testing LogExtentLists\n");

// LogExtentLists testing:
    
    LogExtentList lel(lv);

    printf("Building 100-entry LogExtentList...");

    for (i = 0; i<100; i++) {
        le.reinit(le.partitionp(),i,le.blockSize()*(100-i)-i,err);
        // le.startBlock(i);
        // le.numBlocks(100-i);
        // le.infoLen(le.blockMultLen()-i);
        if ( err ) {
            fprintf( stderr,"LogExtentList.reinit(%ld,%ld) error: %s\n",
                     i,le.blockSize()*(100-i)-i,err.message() );
            return -20;
        }
        lel.append(le,err);
        if ( err ) {
            fprintf( stderr,"LogExtentList.append() error: %s\n",err.message() );
            return -9;
        }
    }

    printf("Done.\n");

    const LogExtent * lep;

    printf("Comparing LogExtents using at() ...\n");
    for (i = 0; i<100; i++) {
        lep = lel.at(i,err);
        if ( err ) {
            fprintf(stderr,"LogExtentList construction error: %s\n",
                    err.message());
            return -10;
        }
        if (i != lep->startBlock()) {
            fprintf(stderr," Block Mismatch: lel[%ld].sect == %ld\n",
                   i,lep->startBlock());
            mismatches ++;
        }
        if ((100-i) != lep->numBlocks()) {
            fprintf(stderr," Block Mismatch: lel[%ld].nb == %ld\n",
                   i,lep->numBlocks());
            mismatches ++;
        }
        if ( lep->unusedLen() != i ) {
            fprintf(stderr," Block Mismatch: lel[%ld].il == %ld\n",
                   i,lep->infoLen());
            mismatches ++;
        }
    }
    if ( mismatches != 0 ) {
        fprintf(stderr,"Test Aborted with %ld mismatches.\n",mismatches);
        return -11;
    }
    printf("Done.\n");

    printf("Testing LogExtentIter\n");

    LogExtentListIter leli(lel);

    printf("Comparing LogExtents using iterator...\n");
    for (i=0,leli.reset(); leli.next();i++) {
        lep = leli.key();
        if (i != lep->startBlock()) {
            fprintf(stderr," Block Mismatch: lel[%ld].sect == %ld\n",
                   i,lep->startBlock());
            mismatches ++;
        }
        if ((100-i) != lep->numBlocks()) {
            fprintf(stderr," Block Mismatch: lel[%ld].nb == %ld\n",
                   i,lep->numBlocks());
            mismatches ++;
        }
        if ( lep->unusedLen() != i ) {
            fprintf(stderr," Block Mismatch: lel[%ld].il == %ld\n",
                   i,lep->infoLen());
            mismatches ++;
        }
    }
    if ( mismatches != 0 ) {
        fprintf(stderr,"Test Aborted with %ld mismatches.\n",mismatches);
        return -12;
    }
    printf("Done.\n");
    printf("Done with LogExtents.\n");
    return 0;
}

