// Concatenation //------------------------------------------------------------------------------ void TestAString::Concatenation() const { // Ensure empty strings are correctly handled // Because an empty AString is a special case pointer to a global empty // buffer, it's read-only { AString a, b; a += b; } { AString a; const char * b = ""; a += b; } { AString a, b; a.Append( b ); } { AString a; const char * b = ""; a.Append( b, 0 ); } }
// ParseNamedVariableName //------------------------------------------------------------------------------ /*static*/ bool BFFParser::ParseVariableName( BFFIterator & iter, AString & name, bool & parentScope ) { // skip over the declaration symbol ASSERT( *iter == BFF_DECLARE_VAR_INTERNAL || *iter == BFF_DECLARE_VAR_PARENT ); parentScope = ( *iter == BFF_DECLARE_VAR_PARENT ); const BFFIterator varNameStart = iter; // include type token in var name iter++; // make sure we haven't hit the end of the file if ( iter.IsAtEnd() ) { Error::Error_1012_UnexpectedEndOfFile( iter ); return false; } if ( *iter == '\'' || *iter == '"' ) { // parse the string const BFFIterator openToken = iter; iter.SkipString( *openToken ); if ( *iter != *openToken ) { Error::Error_1002_MatchingClosingTokenNotFound( openToken, nullptr, *openToken ); return false; } BFFIterator stringStart = openToken; stringStart++; // unescape and subsitute embedded variables AStackString< 256 > value; if ( PerformVariableSubstitutions( stringStart, iter, value ) == false ) { return false; } iter++; // skip close token BFFIterator varNameIter( value.Get(), value.GetLength(), iter.GetFileName().Get(), iter.GetFileTimeStamp() ); // sanity check it is a sensible length if ( value.GetLength() + 1/* '.' will be added */ > MAX_VARIABLE_NAME_LENGTH ) { Error::Error_1014_VariableNameIsTooLong( varNameIter, (uint32_t)value.GetLength(), (uint32_t)MAX_VARIABLE_NAME_LENGTH ); return false; } // sanity check it is a valid variable name while ( varNameIter.IsAtEnd() == false ) { if ( varNameIter.IsAtValidVariableNameCharacter() == false ) { Error::Error_1013_UnexpectedCharInVariableName( varNameIter, nullptr ); return false; } varNameIter++; } // append '.' to variable name name = "."; name.Append( value ); } else { // make sure immediately after the symbol starts a variable name if ( iter.IsAtValidVariableNameCharacter() == false ) { Error::Error_1013_UnexpectedCharInVariableName( iter, nullptr ); return false; } // find the end of the variable name iter.SkipVariableName(); const BFFIterator varNameEnd = iter; // sanity check it is a sensible length size_t varNameLen = varNameStart.GetDistTo( varNameEnd ); if ( varNameLen > MAX_VARIABLE_NAME_LENGTH ) { Error::Error_1014_VariableNameIsTooLong( iter, (uint32_t)varNameLen, (uint32_t)MAX_VARIABLE_NAME_LENGTH ); return false; } // store variable name name.Assign( varNameStart.GetCurrent(), varNameEnd.GetCurrent() ); } ASSERT( name.GetLength() > 0 ); if ( parentScope ) { // exchange '^' with '.' ASSERT( BFF_DECLARE_VAR_PARENT == name[0] ); name[0] = BFF_DECLARE_VAR_INTERNAL; } return true; }
// EmbeddedNuls //------------------------------------------------------------------------------ void TestAString::EmbeddedNuls() const { // Create a string with an embedded nul and check various behaviours AStackString<> string( "0123456789" ); const uint32_t originalStringLen = string.GetLength(); string[ 5 ] = 0; // insert null terminator // Copy construction { AString copy( string ); TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); } // Assignment (operator =) { AString copy; copy = string; TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); } // Assignment (Assign) { AString copy; copy.Assign( string ); TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); } // Assignment (Assign with iterators) { AString copy; copy.Assign( string.Get(), string.GetEnd() ); TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); } // Append (operator +=) { // Append to empty AString copy; copy += string; TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( AString::StrNCmp( string.Get(), copy.Get(), originalStringLen ) == 0 ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); // Append to existing AString copy2( string ); copy2 += string; TEST_ASSERT( copy2.GetLength() == ( originalStringLen * 2 ) ); TEST_ASSERT( memcmp( "01234" "\0" "678901234" "\0" "6789", copy2.Get(), ( originalStringLen * 2 ) ) == 0 ); } // Append (Append) { // Append to empty AString copy; copy.Append( string ); TEST_ASSERT( copy.GetLength() == originalStringLen ); TEST_ASSERT( memcmp( "01234" "\0" "6789", copy.Get(), originalStringLen ) == 0 ); // Append to existing AString copy2( string ); copy2.Append( string ); TEST_ASSERT( copy2.GetLength() == ( originalStringLen * 2 ) ); TEST_ASSERT( memcmp( "01234" "\0" "678901234" "\0" "6789", copy2.Get(), ( originalStringLen * 2 ) ) == 0 ); } }