//将Tag翻译为字符串,此处的Tag就是键值对中的键
LPWSTR ReadTagString(char *tagString)//pdf中#23代表'#'
{
	int index = 0;
	int len=(int)strlen(tagString);
	List output=InitList();//每个data是byte值
	while (index < len)
	{
		if (tagString[index] != '#')
		{
			AddNode(output,(void*)tagString[index] );
			index++;
		}
		else
		{
			if (tagString[index + 1] == '#')//正常pdf几乎不可能遇到的情况,两个#相连
			{
				AddNode(output,(void*)'#');
				AddNode(output,(void*)'#');
				index += 2;
			}
			else
			{
				if (!TestValid(Substring(tagString,index + 1, 2)))//如果不符合#00~#FF的形式,原样输出,正常pdf几乎不可能遇到的情况
				{
					AddNode(output,(void*)'#');
					AddNode(output,(void*)tagString[index+1]);
					AddNode(output,(void*)tagString[index+2]);
					index+=3;
				}
				else
				{
					AddNode(output,(void*)GetDecimal(Substring(tagString,index + 1, 2)));
					index += 3;
				}
			}
		}
	}
	return UTF8ToUnicode(CharListGetString(output));
}
Example #2
0
bool FManifestTest::RunTest( const FString& Parameters )
{
	// Key metadata
	TSharedPtr< FLocMetadataObject > KeyMetadataA = MakeShareable( new FLocMetadataObject );
	TSharedPtr< FLocMetadataObject > KeyMetadataB = MakeShareable( new FLocMetadataObject );

	// Info metadata
	TSharedPtr< FLocMetadataObject > InfoMetadataA = MakeShareable( new FLocMetadataObject );
	TSharedPtr< FLocMetadataObject > InfoMetadataB = MakeShareable( new FLocMetadataObject );

	// Source metadata
	TSharedPtr< FLocMetadataObject > SourceMetadataA = MakeShareable( new FLocMetadataObject );
	TSharedPtr< FLocMetadataObject > SourceMetadataB = MakeShareable( new FLocMetadataObject );


	// Setup KeyMetadataA
	KeyMetadataA->SetStringField( TEXT("Gender"			),	TEXT("Masculine")	);
	KeyMetadataA->SetStringField( TEXT("Plurality"		),	TEXT("Singular")	);
	KeyMetadataA->SetStringField( TEXT("TargetGender"	),	TEXT("Masculine")	);
	KeyMetadataA->SetStringField( TEXT("TargetPlurality"),	TEXT("Singular")	);

	// Setup KeyMetadataB
	KeyMetadataB->SetStringField( TEXT("Gender"			),	TEXT("Masculine")	);
	KeyMetadataB->SetStringField( TEXT("Plurality"		),	TEXT("Singular")	);
	KeyMetadataB->SetStringField( TEXT("TargetGender"	),	TEXT("Feminine")	);
	KeyMetadataB->SetStringField( TEXT("TargetPlurality"),	TEXT("Singular")	);

	// Setup source metadata
	SourceMetadataA->SetBoolField( TEXT("*IsMature"), false );
	SourceMetadataB->SetBoolField( TEXT("*IsMature"), true );

	// Set InfoMetadataA
	InfoMetadataA->SetStringField( TEXT("VoiceActorDirection"), TEXT("Go big or go home!") );

	// Test FInternationalizationManifest
	{
		FContext ContextA;
		ContextA.Key			= TEXT("KeyA");
		ContextA.SourceLocation = TEXT("SourceLocationA");
		ContextA.InfoMetadataObj = MakeShareable( new FLocMetadataObject(*InfoMetadataA) );
		ContextA.KeyMetadataObj = MakeShareable( new FLocMetadataObject(*KeyMetadataA) );

		FContext ContextB;
		ContextB.Key			= TEXT("KeyB");
		ContextB.SourceLocation = TEXT("SourceLocationB");
		ContextB.InfoMetadataObj = MakeShareable( new FLocMetadataObject(*InfoMetadataB) );
		ContextB.KeyMetadataObj = MakeShareable( new FLocMetadataObject(*KeyMetadataB) );

		FLocItem Source( TEXT("TestText") );
		Source.MetadataObj = MakeShareable( new FLocMetadataObject(*SourceMetadataA) );

		FString TestNamespace = TEXT("TestNamespace");


		// Adding entries with exactly matching Source and matching Context
		{
			FInternationalizationManifest TestManifest;

			TestManifest.AddSource( TestNamespace, Source, ContextA );
			bool bResult = TestManifest.AddSource( TestNamespace, Source, ContextA );

			// Adding a duplicate entry reports success but our entry count is not increased after the first entry is added
			TestTrue( TEXT("AddSource result == true"), bResult);
			TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );
		}

		// Adding entries with exactly matching Source but different Contexts
		{
			FInternationalizationManifest TestManifest;

			TestManifest.AddSource( TestNamespace, Source, ContextA );
			TestManifest.AddSource( TestNamespace, Source, ContextB );

			TestEqual( TEXT("ManifestCount == 2"), CountManifestEntries(TestManifest), 2 );

			// Test find by context
			TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryByContext( TestNamespace, ContextA );
			if( !FoundEntry1.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryByContext."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry1->Source == Source );
				TestEqual( TEXT("FoundEntry->Context.Num() == 2"), FoundEntry1->Contexts.Num(), 2);
			}

			TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryByContext( TestNamespace, ContextB );
			if( !FoundEntry2.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryByContext."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry2->Source == Source );
				TestEqual( TEXT("FoundEntry->Context.Num() == 2"), FoundEntry2->Contexts.Num(), 2);
			}

			// Test find by source
			TSharedPtr< FManifestEntry > FoundEntry3 = TestManifest.FindEntryBySource( TestNamespace, Source );
			if( !FoundEntry3.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryBySource."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry3->Source == Source );
				TestEqual( TEXT("FoundEntry->Context.Num() == 2"), FoundEntry3->Contexts.Num(), 2);
			}

			TestTrue( TEXT("FoundEntry1 == FoundEntry2 == FoundEntry3"), (FoundEntry1 == FoundEntry2) && (FoundEntry1 == FoundEntry3) );

		}



		// Adding entries with Source that is NOT an exact match and matching context
		{
			// Source mismatched by Source Text.
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceA( TEXT("Conflicting TestTextA") );
				FLocItem ConflictingSourceB( TEXT("Conflicting TestTextB") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceA, ContextA );
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceB, ContextA );

				// Adding the second entry reports failure and entry count is not increased
				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );	
			}

			// Source mismatched by standard metadata type (not * prefixed) 
			{
				FInternationalizationManifest ManifestTypeConflict;

				FLocItem ConflictingSourceMetadataTypeA = Source;
				FLocItem ConflictingSourceMetadataTypeB = Source;

				// Set metadata with the same name but different type
				ConflictingSourceMetadataTypeA.MetadataObj->SetBoolField( TEXT("ConflictingType"), true );
				ConflictingSourceMetadataTypeB.MetadataObj->SetStringField( TEXT("ConflictingType"), TEXT("true") );

				ManifestTypeConflict.AddSource( TestNamespace, ConflictingSourceMetadataTypeA, ContextA );
				bool bResult = ManifestTypeConflict.AddSource( TestNamespace, ConflictingSourceMetadataTypeB, ContextA );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(ManifestTypeConflict), 1 );

				// Should not find a match when searching with the second Source we tried to add
				TSharedPtr< FManifestEntry > FoundEntry = ManifestTypeConflict.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeB );
				TestInvalid( TEXT("FoundEntry is not valid"), FoundEntry);

			}

			// Source mismatched by standard metadata value (not * prefixed)
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataValueA = Source;
				FLocItem ConflictingSourceMetadataValueB = Source;

				// Set metadata with the same name and type but different value
				ConflictingSourceMetadataValueA.MetadataObj->SetStringField( TEXT("ConflictingValue"), TEXT("A") );
				ConflictingSourceMetadataValueB.MetadataObj->SetStringField( TEXT("ConflictingValue"), TEXT("B") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueA, ContextA );
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueB, ContextA );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

				// Should not find a match when searching with the second Source we tried to add
				TSharedPtr< FManifestEntry > FoundEntry = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueB );
				TestInvalid( TEXT("FoundEntry is not valid"), FoundEntry);

			}

			// Source mismatched by * prefixed metadata type
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataTypeA = Source;
				FLocItem ConflictingSourceMetadataTypeB = Source;

				// Set metadata with the same name but different type
				ConflictingSourceMetadataTypeA.MetadataObj->SetBoolField( TEXT("*ConflictingType"), true );
				ConflictingSourceMetadataTypeB.MetadataObj->SetStringField( TEXT("*ConflictingType"), TEXT("true") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeA, ContextA );

				// Though the Source items are considered to be a match(they are equal) in this case, the manifest reports this as a conflict
				//  and should not add an entry.  The reason is that AddSource does an 'exact' match check on the metadata object
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeB, ContextA );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

				// We should be able to find the entry using either Source FLocItem
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);


			}

			// Source mismatched by * prefixed metadata value
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataValueA = Source;
				FLocItem ConflictingSourceMetadataValueB = Source;

				// Set metadata with the same name and type but different value
				ConflictingSourceMetadataValueA.MetadataObj->SetStringField( TEXT("*ConflictingValue"), TEXT("A") );
				ConflictingSourceMetadataValueB.MetadataObj->SetStringField( TEXT("*ConflictingValue"), TEXT("B") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueA, ContextA );

				// Thought the Source items are considered to be a match(they are equal) in this case, the manifest reports this as a conflict
				//  and should not add an entry.  The reason is that AddSource does an 'exact' match check on the metadata object
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueB, ContextA );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

				// We should be able to find the entry using either Source FLocItem
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);

			}

		}

		// Adding entries with Source that is NOT an exact match and different context
		{
			// Source mismatched by Source Text.
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceA( TEXT("Conflicting TestTextA") );
				FLocItem ConflictingSourceB( TEXT("Conflicting TestTextB") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceA, ContextA );
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceB, ContextB );

				TestTrue( TEXT("AddSource result == true"), bResult);
				TestEqual( TEXT("ManifestCount == 2"), CountManifestEntries(TestManifest), 2 );

				// We should be able to find two unique entries by source
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);

				TestTrue( TEXT("FoundEntry1 != FoundEntry2"), FoundEntry1 != FoundEntry2 );

				// We should be able to find two unique entries by context
				TSharedPtr< FManifestEntry > FoundEntry3 = TestManifest.FindEntryByContext( TestNamespace, ContextA );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry3);

				TSharedPtr< FManifestEntry > FoundEntry4 = TestManifest.FindEntryByContext( TestNamespace, ContextB );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry4);

				TestTrue( TEXT("FoundEntry3 != FoundEntry4"), FoundEntry3 != FoundEntry4 );

				// Found entry looked up by source A should match entry looked up by context A
				TestTrue( TEXT("FoundEntry1 == FoundEntry3"), FoundEntry1 == FoundEntry3 );

				// Found entry looked up by source B should match entry looked up by context B
				TestTrue( TEXT("FoundEntry2 == FoundEntry4"), FoundEntry2 == FoundEntry4 );

			}

			// Source mismatched by standard metadata type (not * prefixed)
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataTypeA = Source;
				FLocItem ConflictingSourceMetadataTypeB = Source;

				// Set metadata with the same name but different type
				ConflictingSourceMetadataTypeA.MetadataObj->SetBoolField( TEXT("ConflictingType"), true );
				ConflictingSourceMetadataTypeB.MetadataObj->SetStringField( TEXT("ConflictingType"), TEXT("true") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeA, ContextA );
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeB, ContextB );

				TestTrue( TEXT("AddSource result == true"), bResult);
				TestEqual( TEXT("ManifestCount == 2"), CountManifestEntries(TestManifest), 2 );

				// We should be able to find two unique entries by source
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);

				TestTrue( TEXT("FoundEntry1 != FoundEntry2"), FoundEntry1 != FoundEntry2 );

				// We should be able to find two unique entries by context
				TSharedPtr< FManifestEntry > FoundEntry3 = TestManifest.FindEntryByContext( TestNamespace, ContextA );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry3);

				TSharedPtr< FManifestEntry > FoundEntry4 = TestManifest.FindEntryByContext( TestNamespace, ContextB );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry4);

				TestTrue( TEXT("FoundEntry3 != FoundEntry4"), FoundEntry3 != FoundEntry4 );

				// Found entry looked up by source A should match entry looked up by context A
				TestTrue( TEXT("FoundEntry1 == FoundEntry3"), FoundEntry1 == FoundEntry3 );

				// Found entry looked up by source B should match entry looked up by context B
				TestTrue( TEXT("FoundEntry2 == FoundEntry4"), FoundEntry2 == FoundEntry4 );

			}

			// Source mismatched by standard metadata value (not * prefixed)
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataValueA = Source;
				FLocItem ConflictingSourceMetadataValueB = Source;

				// Set metadata with the same name and type but different value
				ConflictingSourceMetadataValueA.MetadataObj->SetStringField( TEXT("ConflictingValue"), TEXT("A") );
				ConflictingSourceMetadataValueB.MetadataObj->SetStringField( TEXT("ConflictingValue"), TEXT("B") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueA, ContextA );
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueB, ContextB );

				TestTrue( TEXT("AddSource result == true"), bResult);
				TestEqual( TEXT("ManifestCount == 2"), CountManifestEntries(TestManifest), 2 );

				// We should be able to find two unique entries by source
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);

				TestTrue( TEXT("FoundEntry1 != FoundEntry2"), FoundEntry1 != FoundEntry2 );

				// We should be able to find two unique entries by context
				TSharedPtr< FManifestEntry > FoundEntry3 = TestManifest.FindEntryByContext( TestNamespace, ContextA );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry3);

				TSharedPtr< FManifestEntry > FoundEntry4 = TestManifest.FindEntryByContext( TestNamespace, ContextB );
				TestValid( TEXT("FoundEntry3 is valid"), FoundEntry4);

				TestTrue( TEXT("FoundEntry3 != FoundEntry4"), FoundEntry3 != FoundEntry4 );

				// Found entry looked up by source A should match entry looked up by context A
				TestTrue( TEXT("FoundEntry1 == FoundEntry3"), FoundEntry1 == FoundEntry3 );

				// Found entry looked up by source B should match entry looked up by context B
				TestTrue( TEXT("FoundEntry2 == FoundEntry4"), FoundEntry2 == FoundEntry4 );

			}

			// Source mismatched by * prefixed metadata type
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataTypeA = Source;
				FLocItem ConflictingSourceMetadataTypeB = Source;

				// Set metadata with the same name but different type
				ConflictingSourceMetadataTypeA.MetadataObj->SetBoolField( TEXT("*ConflictingType"), true );
				ConflictingSourceMetadataTypeB.MetadataObj->SetStringField( TEXT("*ConflictingType"), TEXT("true") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeA, ContextA );

				// Though the Source items are considered to be a match(they are equal) in this case, the manifest reports this as a conflict
				//  and should not add an entry.  The reason is that AddSource does an 'exact' match check on the metadata object
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataTypeB, ContextB );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

				// We should be able to find the entry using either Source FLocItem
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataTypeB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);
			}

			// Source mismatched by * prefixed metadata value
			{
				FInternationalizationManifest TestManifest;

				FLocItem ConflictingSourceMetadataValueA = Source;
				FLocItem ConflictingSourceMetadataValueB = Source;

				// Set metadata with the same name and type but different value
				ConflictingSourceMetadataValueA.MetadataObj->SetStringField( TEXT("*ConflictingValue"), TEXT("A") );
				ConflictingSourceMetadataValueB.MetadataObj->SetStringField( TEXT("*ConflictingValue"), TEXT("B") );

				TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueA, ContextA );

				// Thought the Source items are considered to be a match(they are equal) in this case, the manifest reports this as a conflict
				//  and should not add an entry.  The reason is that AddSource does an 'exact' match check on the metadata object
				bool bResult = TestManifest.AddSource( TestNamespace, ConflictingSourceMetadataValueB, ContextB );

				TestFalse( TEXT("AddSource result == false"), bResult);
				TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

				// We should be able to find the entry using either Source FLocItem
				TSharedPtr< FManifestEntry > FoundEntry1 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueA );
				TestValid( TEXT("FoundEntry1 is valid"), FoundEntry1);

				TSharedPtr< FManifestEntry > FoundEntry2 = TestManifest.FindEntryBySource( TestNamespace, ConflictingSourceMetadataValueB );
				TestValid( TEXT("FoundEntry2 is valid"), FoundEntry2);

			}

		}

		// Adding an entry that only differs in the optional flag 
		{
			FInternationalizationManifest TestManifest;

			// Reports success and our entry count does not change.  bIsOptional is not a key and is not used during lookup.  When
			//  we AddSource, we find an existing matching entry so AddSource returns true but no new entry is added.  The original
			//  entry's bIsOptional value is not updated.
			FContext ContextConflictingOptionalFlag = ContextA;
			ContextConflictingOptionalFlag.bIsOptional = !ContextA.bIsOptional;

			TestManifest.AddSource( TestNamespace, Source, ContextA );
			bool bResult = TestManifest.AddSource( TestNamespace, Source, ContextConflictingOptionalFlag);

			TestTrue( TEXT("AddSource result == true"), bResult);
			TestEqual( TEXT("ManifestCount == 1"), CountManifestEntries(TestManifest), 1 );

			// We should be able to look up the existing entry using the ContextConflictingOptionalFlag context but the entries bIsOptional flag will match ContextA
			TSharedPtr< FManifestEntry > FoundEntry = TestManifest.FindEntryByContext( TestNamespace, ContextConflictingOptionalFlag );
			if( !FoundEntry.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryByContext."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->bIsOptional == ContextA->bIsOptional"), FoundEntry->Contexts[0].bIsOptional == ContextA.bIsOptional );
			}
		}

		// Add an entry with null key metadata to see if we can retrieve it with non-null but empty key metadata
		{
			FInternationalizationManifest TestManifest;

			FContext ContextC;
			ContextC.Key			= TEXT("KeyC");
			ContextC.SourceLocation = TEXT("SourceLocationC");
			ContextC.InfoMetadataObj = MakeShareable( new FLocMetadataObject(*InfoMetadataB) );
			ContextC.KeyMetadataObj = NULL;

			Source.MetadataObj = NULL;
			TestManifest.AddSource( TestNamespace, Source, ContextC );

			//  Now give our context and source valid but empty metadata
			ContextC.KeyMetadataObj = MakeShareable( new FLocMetadataObject() );
			Source.MetadataObj = MakeShareable( new FLocMetadataObject() );

			// Ensure we find the entry we added by source
			TSharedPtr< FManifestEntry > FoundEntry;
			FoundEntry = TestManifest.FindEntryBySource( TestNamespace, Source );
			if( !FoundEntry.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryBySource."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == Source );
			}

			// Ensure we find the entry we added by context
			FoundEntry = TestManifest.FindEntryByContext( TestNamespace, ContextC );
			if( !FoundEntry.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryByContext."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == Source );
			}
		}

		// Add an entry with non-null but empty key metadata and see if we can retrieve null metadata
		{
			FInternationalizationManifest TestManifest;

			FContext ContextC;
			ContextC.Key			= TEXT("KeyC");
			ContextC.SourceLocation = TEXT("SourceLocationC");
			ContextC.InfoMetadataObj = MakeShareable( new FLocMetadataObject(*InfoMetadataB) );
			ContextC.KeyMetadataObj = MakeShareable( new FLocMetadataObject());

			Source.MetadataObj = MakeShareable( new FLocMetadataObject());
			TestManifest.AddSource( TestNamespace, Source, ContextC );

			//  Now give our context and source Null metadata
			ContextC.KeyMetadataObj = NULL;
			Source.MetadataObj = NULL;

			// Ensure we find the entry we added by source
			TSharedPtr< FManifestEntry > FoundEntry;
			FoundEntry = TestManifest.FindEntryBySource( TestNamespace, Source );
			if( !FoundEntry.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryBySource."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == Source );
			}

			// Ensure we find the entry we added by context
			FoundEntry = TestManifest.FindEntryByContext( TestNamespace, ContextC );
			if( !FoundEntry.IsValid() )
			{
				AddError(TEXT("FManifestEntry could not find entry using FindEntryByContext."));
			}
			else
			{
				TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == Source );
			}
		}
	}

	return true;
}