//-*-c++-*--------------------------------------------------------------
//  attrTest.cpp
//   Tests Attributes class.
//
//      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/descrTst/attrTest.cpp,v $
// $Revision: 1.9 $     $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/05/08 15:23:22 $
//

//#include <stdlib.h>
//#include <string.h>

#include "nsrLib.h"
// Should we need to force these includes?
//#include "descr/nsrAttr.h"
//#include "descr/nsrFile.h"

// WE NEED THE FOLLOWING INITIALIZED (just because the descrTest
//   infrastructure requires it, this test DOES NOT.)  --CSB, 9-18-95
static const int BUFLEN = 8192;

printError(const char* msg){ printf("%s\n",msg);}

// NOTE:  We define the enum boundaries with "tstFirstBit" and "tstLastBit"
//   so that we can process all these bits in a loop.
enum AttrBit
{
   tstFirstBit                           =0,
   tstMiscSortedDirectoryBitPosition     =0,
   tstMiscNonRelocatableBitPosition        ,
   tstMiscArchiveBitPosition               ,
   tstMiscSetUidBitPosition                ,
   tstMiscSetGidBitPosition                ,
   tstMiscStickyBitPosition                ,
   tstMiscContiguousBitPosition            ,
   tstMiscSystemBitPosition                ,
   tstMiscTransformedBitPosition           ,
   tstMiscMultiVersionsBitPosition         ,
   tstPermOthDeleteBitPosition             ,
   tstPermOthChattrBitPosition             ,
   tstPermOthReadBitPosition               ,
   tstPermOthWriteBitPosition              ,
   tstPermOthExecuteBitPosition            ,
   tstPermGrpDeleteBitPosition             ,
   tstPermGrpChattrBitPosition             ,
   tstPermGrpReadBitPosition               ,
   tstPermGrpWriteBitPosition              ,
   tstPermGrpExecuteBitPosition            ,
   tstPermOwnDeleteBitPosition             ,
   tstPermOwnChattrBitPosition             ,
   tstPermOwnReadBitPosition               ,
   tstPermOwnWriteBitPosition              ,
   tstPermOwnExecuteBitPosition            ,
   tstLastBit                             =tstPermOwnExecuteBitPosition
};

// Print out which bit we are working with.
void printWhichBit(AttrBit whichBit)
{
  switch (whichBit)
  {
    case tstMiscSortedDirectoryBitPosition       :
      printf("tstMiscSortedDirectoryBitPosition\n");break;
    case tstMiscNonRelocatableBitPosition        :
      printf("tstMiscNonRelocatableBitPosition\n");break;
    case tstMiscArchiveBitPosition               :
      printf("tstMiscArchiveBitPosition\n");break;
    case tstMiscSetUidBitPosition                :
      printf("tstMiscSetUidBitPosition\n");break;
    case tstMiscSetGidBitPosition                :
      printf("tstMiscSetGidBitPosition\n");break;
    case tstMiscStickyBitPosition                :
      printf("tstMiscStickyBitPosition\n");break;
    case tstMiscContiguousBitPosition            :
      printf("tstMiscContiguousBitPosition\n");break;
    case tstMiscSystemBitPosition                :
      printf("tstMiscSystemBitPosition\n");break;
    case tstMiscTransformedBitPosition           :
      printf("tstMiscTransformedBitPosition\n");break;
    case tstMiscMultiVersionsBitPosition         :
      printf("tstMiscMultiVersionsBitPosition\n");break;
    case tstPermOthDeleteBitPosition             :
      printf("tstPermOthDeleteBitPosition\n");break;
    case tstPermOthChattrBitPosition             :
      printf("tstPermOthChattrBitPosition\n");break;
    case tstPermOthReadBitPosition               :
      printf("tstPermOthReadBitPosition\n");break;
    case tstPermOthWriteBitPosition              :
      printf("tstPermOthWriteBitPosition\n");break;
    case tstPermOthExecuteBitPosition            :
      printf("tstPermOthExecuteBitPosition\n");break;
    case tstPermGrpDeleteBitPosition             :
      printf("tstPermGrpDeleteBitPosition\n");break;
    case tstPermGrpChattrBitPosition             :
      printf("tstPermGrpChattrBitPosition\n");break;
    case tstPermGrpReadBitPosition               :
      printf("tstPermGrpReadBitPosition\n");break;
    case tstPermGrpWriteBitPosition              :
      printf("tstPermGrpWriteBitPosition\n");break;
    case tstPermGrpExecuteBitPosition            :
      printf("tstPermGrpExecuteBitPosition\n");break;
    case tstPermOwnDeleteBitPosition             :
      printf("tstPermOwnDeleteBitPosition\n");break;
    case tstPermOwnChattrBitPosition             :
      printf("tstPermOwnChattrBitPosition\n");break;
    case tstPermOwnReadBitPosition               :
      printf("tstPermOwnReadBitPosition\n");break;
    case tstPermOwnWriteBitPosition              :
      printf("tstPermOwnWriteBitPosition\n");break;
    case tstPermOwnExecuteBitPosition            :
      printf("tstPermOwnExecuteBitPosition\n");break;
    default:
      printf("I don't know which bit.\n");break;
  }
}

UINT16 testAttributesSuites(void);
UINT16 makeAttributesAndTest(UINT32 uid, UINT32 gid, time_t accessTime, 
  time_t modificationTime, time_t attributeTime, UINT16 linkCount,
  UINT16 unixMode, FileType fileType);
UINT16 testAttributes(Attributes& attr);
UINT16 testNonBitAttributes(Attributes& attr);
UINT16 testAllBits(Attributes& attr);
UINT16 testBit(Attributes& attr, AttrBit whichBit);
void toggleBit(Attributes& attr, AttrBit whichBit);
UINT16 testAppend(Attributes& attr);

///////////////////////////////////////////////////////////////////////////
// Usage: attrTest
UINT16 main (UINT16 argc, CHAR_PTR argv[])
{
  // Do the FileEntry tests.
  UINT16 numFailedTests;
  numFailedTests = testAttributesSuites();

  if(numFailedTests)
    printf("FAILURE:  in main(): %d tests failed.\n", numFailedTests);

  return numFailedTests;
}

//--------------------------------------------
// t e s t A t t r i b u t e s S u i t e s ( ) 
// Test the Attributes with various data states.
UINT16 testAttributesSuites(void)
{
  UINT16 numFailedTests = 0;

  numFailedTests += makeAttributesAndTest(
    0x00000000,              // uid
    0x00000000,              // gid
    time(0)-1,               // accessTime
    time(0),                 // modificationTime
    time(0)+1,               // attributesTime
    0x00000000,              // linkCount
    0x0000,                  // unixMode
    file_ExtendedAttributes);       // fileType

  numFailedTests += makeAttributesAndTest(
    0x00000001,              // uid
    0x00000002,              // gid
    time(0)-1,               // accessTime
    time(0),                 // modificationTime
    time(0)+1,               // attributesTime
    0x0007,          // linkCount
    0x5555,                  // unixMode
    file_Unspecified);       // fileType

  numFailedTests += makeAttributesAndTest(
    ~0x00000001,             // uid
    ~0x00000002,             // gid
    time(0)-100,             // accessTime
    time(0),                 // modificationTime
    time(0)+100,             // attributesTime
    ~0x0006,         // linkCount
    ~0x5555,                 // unixMode
    file_Directory);    // fileType

#if 0  // The following test will break TimeZone problems with
//  the modificationTime.
  numFailedTests += makeAttributesAndTest(
    0x00000002,              // uid
    0x00000002,              // gid
    812051630,               // accessTime
    724326181,                       // modificationTime
    810446160,               // attributesTime
    ~0x0001,         // linkCount
    ~0x5555,                 // unixMode
    file_Directory);    // fileType
#endif

  return numFailedTests;
}

//-----------------------------------------------
// m a k e A t t r i b u t e s A n d  T e s t ( )
// NOTE:  We should also provide an initialization to the bits not set
//   in UnixMode.
UINT16 makeAttributesAndTest(UINT32 uid, UINT32 gid, time_t accessTime, 
  time_t modificationTime, time_t attributeTime, UINT16 linkCount,
  UINT16 unixMode, FileType fileType)
{
  // TEST PLAN:
  // We will instantiate the FileEntry and Attributes classes,
  //   and confirm the Attributes classes are correctly written
  //   to and read from the FileEntry class.  Also, the Attributes
  //   will be changed and written/read, and then changed back
  //   and written/read to confirm we can successfully change
  //   back and forth specific attributes.
  // NOTE:  At this highest level, we will pass around the
  //   Attributes class.  The lower levels instantiate the FileEntry
  //   as needed.
  Attributes attr, originalAttrib;
  UINT16 numFailedTests = 0;

  // Set up some test data.
  // NOTE:  For these tests, the best test data will have unique values across all the
  //   fields.
  attr.uid(uid);
  attr.gid(gid);
  attr.accessTime(accessTime);
  attr.modificationTime(modificationTime);
  attr.attributeTime(attributeTime);
  attr.linkCount(linkCount);
  attr.unixMode(unixMode);
  attr.fileType(fileType);
  
  // Keep a copy of the original for comparison later.
  originalAttrib = attr;

  // DO THE TESTS.
  numFailedTests += testAttributes(attr);

  if(numFailedTests)
    printError("Attributes test FAILED in makeAttributesAndTest().");

  if(originalAttrib != attr)
  { // If the Attributes was modified during the test, this is a problem.
    printError("FAILURE:  Attributes not restored to original state in makeAttributesAndTest().");
  }

  return numFailedTests;
} 

//--------------------------------
// t e s t A t t r i b u t e s ( )
// Test the Attributes passed in, and return the number of failed tests.
UINT16 testAttributes(Attributes& attr)
{
  UINT16 numFailedBit;
  UINT16 numFailedNonBit;
  UINT16 numFailedAppend;
  
  // DO THE TESTS.
  numFailedNonBit = testNonBitAttributes(attr);
  if(numFailedNonBit)
  {
    printError("Attributes test FAILED in testAttributes() [testNonBitAttributes()]");
  }

  numFailedBit = testAllBits(attr);
  if(numFailedBit)
  {
    printError("Attributes test FAILED in testAttributes() [testAllBits()]");
  }

  // Test the append and set by string members.
  numFailedAppend = testAppend(attr);
  
  return numFailedBit + numFailedNonBit  + numFailedAppend;
}

//--------------------------------------------
// t e s t N o n B i t A t t r i b u t e s ( )
// This function tests all non-bit attributes for the Attributes passed in.
// NOTE:  This function returns the number of the tests that failed.
// NOTE:  In the first pass, We are testing one attribute at a time.  This
//   confirms we can logically change one attribute.  In the second pass,
//   we are testing all attributes at a time.  This confirms we uniquely
//   change each attribute without impacting other attributes, if we assume
//   adequate test data (each attribute must have a unique state separate
//   from all other attributes, so a "collision" of state will be detected).
UINT16 testNonBitAttributes(Attributes& attr)
{
  Attributes originalAttrib = attr;
  UINT16 numFailedTests = 0;

  // Each individual field test does the following:
  //   ASSIGN     B = A
  //   CHANGE     A
  // * TEST:      A != B
  //   UNCHANGE   A
  // * TEST:      A == B
  // This test will confirm that we are retrieving the data member we are setting,
  //   we are setting the data member we are retrieveing, and we are able to change
  //   the correct value stored for this data field.
  // NOTE:  To verify we are setting the correct physical field for this data
  //   value, we must change multiple fields, test, and un-change multiple fields.
  //   (This happens in part two).
  // NOTE:  We DO NOT write to and read from a FileEntry because the field
  //   FileType will not be the same:  If set to an erroneous type, it will
  //   be written to the FileEntry as an InvalidType.  (We could do this for
  //   the other types, however;  we don't now, though.

  attr.uid(~ attr.uid());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set uid to complement in testNonBitAttributes().");
  }
  attr.uid(~ attr.uid());
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore uid from complement in testNonBitAttributes().");
  }
  
  attr.gid(~ attr.gid());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set gid to complement in testNonBitAttributes().");
  }
  attr.gid(~ attr.gid());
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore gid from complement in testNonBitAttributes().");
  }
  
  attr.accessTime(~ attr.accessTime());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set accessTime to complement in testNonBitAttributes().");
  }
  attr.accessTime(~ attr.accessTime());
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore accessTime from complement in testNonBitAttributes().");
  }
  
  attr.modificationTime(~ attr.modificationTime());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set modificationTime to complement in testNonBitAttributes().");
  }
  attr.modificationTime(~ attr.modificationTime());
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore modificationTime from complement in testNonBitAttributes().");
  }
  
  attr.attributeTime(~ attr.attributeTime());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set uid attributeTime complement in testNonBitAttributes().");
  }
  attr.attributeTime(~ attr.attributeTime());
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore attributeTime from complement in testNonBitAttributes().");
  }
  
  attr.linkCount(~ attr.linkCount());
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set linkCount to complement in testNonBitAttributes().");
  }

  attr.linkCount(~ (attr.linkCount()));
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore linkCount from complement in testNonBitAttributes().");
  }
  
#ifdef ATTR_TEST_DBUG
  {   RWCString cstr;
      printf("%s\n", attr.appendAttributes(cstr = "attr"));
      printf("%s\n", originalAttrib.appendAttributes(cstr = "origAttrib"));
  }
  
#endif
  attr.unixMode(~ (attr.unixMode()));
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set unixMode to complement in testNonBitAttributes().");
  }

#ifdef ATTR_TEST_DBUG
  {   RWCString cstr;
      printf("%s\n", attr.appendAttributes(cstr = "After unixMode set to complement"));
  }
#endif
  attr.unixMode(~ attr.unixMode());
#ifdef ATTR_TEST_DBUG
  {   RWCString cstr;
      printf("%s\n", attr.appendAttributes(cstr =
                                             "After unxiMode restored through complement:"));
  }
#endif
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore unixMode from complement in testNonBitAttributes().");
  }
  
  // NOTE:  For FileType, we must test specific enumerated values.
  // TEST A VALID TYPE.
  FileType originalFileType = attr.fileType();

  if(originalFileType == file_Unspecified)
  { // If we are an unspecified file, change to something else.
    attr.fileType(file_Raw);
    if(attr == originalAttrib)
    { numFailedTests++;
      printError("ERROR: Could not set fileType to file_Raw in testNonBitAttributes().");
    }
    attr.fileType( originalFileType);
    if(attr != originalAttrib)
    { numFailedTests++;
      printError("ERROR: Could not restore fileType from file_Raw in testNonBitAttributes().");
    }
  }
  else
  { // Change to a file_Unspecified (we were not this before).
    attr.fileType(file_Unspecified);
    if(attr == originalAttrib)
    { numFailedTests++;
      printError("ERROR: Could not set fileType to file_Unspecified in testNonBitAttributes().");
    }
    attr.fileType( originalFileType);
    if(attr != originalAttrib)
    { numFailedTests++;
      printError("ERROR: Could not restore fileType from file_Unspecified in testNonBitAttributes().");
    }
  }
  
  // TEST AN INVALID TYPE.
  originalFileType = attr.fileType();  // Confirm we can retrieve the original type.
  attr.fileType((FileType)0xFF);  // Set an invalid type.
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not set fileType to invalid type in testNonBitAttributes().");
  }
  attr.fileType(originalFileType);
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not restore fileType from invalid type in testNonBitAttributes().");
  }

  // END FIELD TESTS (PART ONE).----------------------------------------------------------------
  // At this point, we tested individual elements.  We should change all elements, restore
  //   all elements, and make sure the attributes structure is still like the original.  (This
  //   test would catch multiple logical fields mapping to one physical field, assuming we
  //   have good test data where each data field has a unique value.)
  // Change all the elements.
  attr.uid(~ attr.uid());
  attr.gid(~ attr.gid());
  attr.accessTime(~ attr.accessTime());
  attr.modificationTime(~ attr.modificationTime());
  attr.attributeTime(~ attr.attributeTime());
  attr.linkCount(~ attr.linkCount());
  attr.unixMode(~ attr.unixMode());
  if((originalFileType = attr.fileType()) == file_Unspecified)
    attr.fileType(file_Raw);
  else
    attr.fileType(file_Unspecified);
  
  // Confirm we don't have the same state.
  if(attr == originalAttrib)
  { numFailedTests++;
    printError("ERROR: Could not change state with all attributes in testNonBitAttributes().");
  }

  // Now, put the state back. 
  attr.uid(~ attr.uid());
  attr.gid(~ attr.gid());
  attr.accessTime(~ attr.accessTime());
  attr.modificationTime(~ attr.modificationTime());
  attr.attributeTime(~ attr.attributeTime());
  attr.linkCount(~ attr.linkCount());
  attr.unixMode(~ attr.unixMode());
  attr.fileType(originalFileType);
  
  // Confirm we have the original state.
  // Confirm we don't have the same state.
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: Attribute collision:  could not restore original state in testNonBitAttributes().");
  }

  return numFailedTests;
}

//--------------------------
// t e s t A l l B i t s ( )
// Return non-zero if all bits are tested correctly, zero otherwise.
// NOTE:  This function returns the number of the tests that failed.
UINT16 testAllBits(Attributes& attr)
{
  // Make an attr just like the original one.
  Attributes originalAttrib = attr;
  UINT16 numFailedTests = 0;
  UINT16 i;  // Loop counter.

  // Test all of the bits in one loop.
  for(i=tstFirstBit; i< tstLastBit; i++)
  { // For each bit we must test.
    numFailedTests += testBit(attr, (AttrBit) i);
  }
#if 0 // If the loop above works, then we don't need this.
  numFailedTests += testBit(attr, tstMiscSortedDirectoryBitPosition);
  numFailedTests += testBit(attr, tstMiscNonRelocatableBitPosition );
  numFailedTests += testBit(attr, tstMiscArchiveBitPosition        );
  numFailedTests += testBit(attr, tstMiscSetUidBitPosition         );
  numFailedTests += testBit(attr, tstMiscSetGidBitPosition         );
  numFailedTests += testBit(attr, tstMiscStickyBitPosition         );
  numFailedTests += testBit(attr, tstMiscContiguousBitPosition     );
  numFailedTests += testBit(attr, tstMiscSystemBitPosition         );
  numFailedTests += testBit(attr, tstMiscTransformedBitPosition    );
  numFailedTests += testBit(attr, tstMiscmultiVersionsBitPosition  );
  numFailedTests += testBit(attr, tstPermOthDeleteBitPosition      );
  numFailedTests += testBit(attr, tstPermOthChattrBitPosition      );
  numFailedTests += testBit(attr, tstPermOthReadBitPosition        );
  numFailedTests += testBit(attr, tstPermOthWriteBitPosition       );
  numFailedTests += testBit(attr, tstPermOthExecuteBitPosition     );
  numFailedTests += testBit(attr, tstPermGrpDeleteBitPosition      );
  numFailedTests += testBit(attr, tstPermGrpChattrBitPosition      );
  numFailedTests += testBit(attr, tstPermGrpReadBitPosition        );
  numFailedTests += testBit(attr, tstPermGrpWriteBitPosition       );
  numFailedTests += testBit(attr, tstPermGrpExecuteBitPosition     );
  numFailedTests += testBit(attr, tstPermOwnDeleteBitPosition      );
  numFailedTests += testBit(attr, tstPermOwnChattrBitPosition      );
  numFailedTests += testBit(attr, tstPermOwnReadBitPosition        );
  numFailedTests += testBit(attr, tstPermOwnWriteBitPosition       );
  numFailedTests += testBit(attr, tstPermOwnExecuteBitPosition     );
#endif

  // Confirm we did not modify our Attributes object.
  if(attr != originalAttrib)
  { numFailedTests++;
    printError("ERROR: testBit() changed the state of Attributes in testAllBits().");
  }

  // We now tested all the bits one at a time.  Now, we should toggle all
  //   the bits directly, test, then all off again, test, and see if we
  //   come up with the same Attributes structure.  This will test if we
  //   are setting the same physical bit for more than one logical bit
  //   actually the test fails for setting one physical bit by an odd-number
  //   of logical bits).
  for(i= tstFirstBit; i< tstLastBit; i++)
  { // For each bit we must toggle.
    toggleBit(attr, (AttrBit) i);
  }

  // Now, test all the bits.
  for(i=tstFirstBit; i< tstLastBit; i++)
  { // For each bit we must test.
    numFailedTests += testBit(attr, (AttrBit) i);
  }

  // Now, we must toggle all the bits back to their original state.
  for(i= tstFirstBit; i< tstLastBit; i++)
  { // For each bit we must toggle.
    toggleBit(attr, (AttrBit) i);
  }

  // Now, test all the bits again in their original state.
  for(i=tstFirstBit; i< tstLastBit; i++)
  { // For each bit we must test.
    numFailedTests += testBit(attr, (AttrBit) i);
  }

  return numFailedTests;
}

//------------------
// t e s t B i t ( )
// This function will perform the following tests for one bit (in order), 
//   reading and writing Attributes to and from FileEntry:
//   READ      A
//   ASSIGN    B=A
//   CHANGE    A
// * TEST:     A != B
//   WRITE     A
//   READ      C
// * TEST:     A == C
//             A != B  (redundant, in case write modifies A)
//             C != B
//   UNCHANGE  A
// * TEST      A == B
//             A != C
//             B != C  (redundant, in case write modifies A)
//   WRITE     A
//   READ      B
// * TEST      A == B
//
// For the tests below, A = attr, B = origAttr, C = readBackAttr.
// NOTE:  The function returns the number of failed tests.
// NOTE:  The attr should have the same state after this call as before,
//   or there was a test failure.
UINT16
testBit(Attributes& attr, AttrBit whichBit)
{
    UINT16 numFailedTests = 0;  // All ok by default.;  
    FileEntry entry, originalEntry;
    Attributes origAttr, readBackAttr;

  // Set the FileEntry with our attributes.
    attr.toFileEntry(entry);
    attr.toFileEntry(originalEntry); // Keep a copy for comparing
                                     // later.
                                     // NOTE: DO NOT use
                                     // FileEntry::operator=()! 
  // Keep a copy of the original.
    origAttr = attr; 

    // Toggle the bit.
    toggleBit(attr, whichBit);

    // TEST: After toggling the bit, attr should not be the same as the original.
#ifdef ATTR_TEST_DBUG
    {   RWCString cstr;
    printf("%s\n", attr.appendAttributes(cstr =
                                         "In testBit() After bit is toggled:"));
    }
#endif
    if(attr == origAttr)
    { numFailedTests++;
    printError("ERROR: toggleBit() did not produce new state in testBit().");
    }

    // Write it out.
    attr.toFileEntry(entry);

    // Now, the is it the same thing?
    readBackAttr.fromFileEntry(entry);

    // TEST:  Check to see that the written and read attributes are the same.
#ifdef ATTR_TEST_DBUG
    {   RWCString cstr;
    printf("%s\n", attr.appendAttributes(cstr = "attr"));
    printf("%s\n", readBackAttr.appendAttributes(cstr = "readBackAttr"));
    }
#endif

    // We expect the attr object to be the same as the read-back class.
    if(attr != readBackAttr)
    { numFailedTests++;
    printError("ERROR:  Read/write error in testBit().");
    }

    // We expect the attr object to be different from the original (since
    //   we toggled the bit).
    // NOTE:  THIS TEST IS IRRELEVANT ON SEVERAL BITS THAT WE MANUALL
    //   FORCE TO ZERO FOR OSTA COMPLIANCE.  
#ifdef ATTR_TEST_DBUG
    {   RWCString cstr;
    printf("%s\n", attr.appendAttributes(cstr = "attr"));
    printf("%s\n", readBackAttr.appendAttributes(cstr = "readBackAttr"));
    }
#endif

    if(!( (whichBit == tstMiscSortedDirectoryBitPosition) ||
          (whichBit == tstMiscNonRelocatableBitPosition)  ||
          (whichBit == tstMiscContiguousBitPosition)  ||
          (whichBit == tstMiscTransformedBitPosition)  ||
          (whichBit == tstMiscMultiVersionsBitPosition))  &&
       (attr.fileType() != file_ExtendedAttributes) ) {
        // We can perform this test ONLY if the bits are not automatically
        //   turned off on the toFileEntry().
        // We expect the attr object to be different from the original (since
        //   we toggled the bit).
        if(attr == origAttr) {
            numFailedTests++;
            printError("ERROR:  After write/read, toggled state not different from original in testBit().");
            {
                RWCString cstr;
                printf("%s\n", attr.appendAttributes(cstr = "attr"));
                printf("%s\n", origAttr.appendAttributes(cstr = "origAttr"));
            }
        }

        // We expect the read-back object to be different from the original
        //   (since it should be like the toggled object).
        if(readBackAttr == origAttr) {
            numFailedTests++;
            printError("ERROR:  Read value not different from different state original in testBit().");
        }

        // Now, toggle the value back. (NOTE:  We toggle back in here, because
        //   we don't want to toggle the bit back if the bit is automatically
        //   turned off in the write toFileEntry().
        toggleBit(attr, whichBit);

        // TEST:  After this second toggle, it should be the same as the
        //   original attribute state we started in.
        if(attr != origAttr) {
            numFailedTests++;
            printError("ERROR:  Cannot return to previous state in testBit().");
        }

        // The un-toggled attr should be different from the toggled attr.
        if(attr == readBackAttr) {
            numFailedTests++;
            printError("ERROR:  Second toggle not different from the first in testBit().");
        }
        // The toggled readBackAttr should (still) be different from the
        //   original, non-toggled origAttr.
        if(origAttr == readBackAttr) {
            numFailedTests++;
            printError("ERROR:  Original state not different from toggled state in testBit().");
        }
  
        // Confirm that we can write and read this original state to and from
        //   the FileEntry (we read this state only before, we did not write it).
        attr.toFileEntry(entry);
  
        // Read it back.
        readBackAttr.fromFileEntry(entry);
  
        // We expect the readBackAttr to be the same as the attr written out.
        if(attr != readBackAttr){
            numFailedTests++;
            printError("ERROR:  Could not write originally read state.");
#ifdef ATTR_TEST_DBUG
            {   RWCString cstr;
            printf("%s\n", attr.appendAttributes(cstr = "attr"));
            printf("%s\n", readBackAttr.appendAttributes(cstr = "readBackAttr"));
            }
            printWhichBit(whichBit);
#endif
        }

        // END, SPECIAL OSTA-SET BITS.
    }

    // Confirm the FileEntry is the way it was in the beginning.
    if(entry != originalEntry) {
        numFailedTests++;
        printError("ERROR:  FileEntry state modified during test.");
    }

    // Return the number of failed tests.
    return numFailedTests;
}

//----------------------
// t o g g l e B i t ( )
// Toggle the enumerated bit passed in for the Attributes
//   object passed in.
void toggleBit(Attributes& attr, AttrBit whichBit)
{
  switch(whichBit)
  {
    case tstMiscSortedDirectoryBitPosition:
      attr.sortedDirectoryBit((attr.sortedDirectoryBit()==True)?False:True); break;
    case tstMiscNonRelocatableBitPosition :
      attr.nonRelocatableBit((attr.nonRelocatableBit()==True)?False:True); break;
    case tstMiscArchiveBitPosition        :
      attr.archiveBit((attr.archiveBit()==True)?False:True); break;
    case tstMiscSetUidBitPosition         :
      attr.setUidBit((attr.setUidBit()==True)?False:True); break;
    case tstMiscSetGidBitPosition         :
      attr.setGidBit((attr.setGidBit()==True)?False:True); break;
    case tstMiscStickyBitPosition         :
      attr.stickyBit((attr.stickyBit()==True)?False:True); break;
    case tstMiscContiguousBitPosition     :
      attr.contiguousBit((attr.contiguousBit()==True)?False:True); break;
    case tstMiscSystemBitPosition         :
      attr.systemBit((attr.systemBit()==True)?False:True); break;
    case tstMiscTransformedBitPosition    :
      attr.transformedBit((attr.transformedBit()==True)?False:True); break;
    case tstMiscMultiVersionsBitPosition  :
      attr.multiVersionsBit((attr.multiVersionsBit()==True)?False:True); break;
    case tstPermOthDeleteBitPosition      :
      attr.permOthDeleteBit((attr.permOthDeleteBit()==True)?False:True); break;
    case tstPermOthChattrBitPosition      :
      attr.permOthChattrBit((attr.permOthChattrBit()==True)?False:True); break;
    case tstPermOthReadBitPosition        :
      attr.permOthReadBit((attr.permOthReadBit()==True)?False:True); break;
    case tstPermOthWriteBitPosition       :
      attr.permOthWriteBit((attr.permOthWriteBit()==True)?False:True); break;
    case tstPermOthExecuteBitPosition     :
      attr.permOthExecuteBit((attr.permOthExecuteBit()==True)?False:True); break;
    case tstPermGrpDeleteBitPosition      :
      attr.permGrpDeleteBit((attr.permGrpDeleteBit()==True)?False:True); break;
    case tstPermGrpChattrBitPosition      :
      attr.permGrpChattrBit((attr.permGrpChattrBit()==True)?False:True); break;
    case tstPermGrpReadBitPosition        :
      attr.permGrpReadBit((attr.permGrpReadBit()==True)?False:True); break;
    case tstPermGrpWriteBitPosition       :
      attr.permGrpWriteBit((attr.permGrpWriteBit()==True)?False:True); break;
    case tstPermGrpExecuteBitPosition     :
      attr.permGrpExecuteBit((attr.permGrpExecuteBit()==True)?False:True); break;
    case tstPermOwnDeleteBitPosition      :
      attr.permOwnDeleteBit((attr.permOwnDeleteBit()==True)?False:True); break;
    case tstPermOwnChattrBitPosition      :
      attr.permOwnChattrBit((attr.permOwnChattrBit()==True)?False:True); break;
    case tstPermOwnReadBitPosition        :
      attr.permOwnReadBit((attr.permOwnReadBit()==True)?False:True); break;
    case tstPermOwnWriteBitPosition       :
      attr.permOwnWriteBit((attr.permOwnWriteBit()==True)?False:True); break;
    case tstPermOwnExecuteBitPosition     :
      attr.permOwnExecuteBit((attr.permOwnExecuteBit()==True)?False:True); break;
    default:
      printf("LOGIC ERROR in toggleBit():   I don't know which bit!\n");
  }
}


UINT16 testAppend(Attributes& attr)
{
    RWCString cstr = "";
    attr.appendAttributes(cstr);

    Attributes newAttr;
    
    newAttr.setAttributes(cstr);
    RWCString newCstr = "";
    newAttr.appendAttributes(newCstr);
    
    if (attr != newAttr){
        printf ("\ntestAppend failed\n%s\n%s\n\n", (char*)cstr, (char*)newCstr);
        return 1;
    }
    
    return 0;
}
