void TestExtHintFieldCreationL(RFs& theFS)
	{
	test.Start(_L("Ext Hint field creation"));


    serv.CopyFileL(KSrcDatabaseFileName, KDatabaseFileName);
	serv.CopyFileL(KSrcDatabaseFileName, KDatabaseSecurePhysicalName);
		
	test.Printf(_L("Checking ExtHintField before loading cntmodel\n"));
	TestTrue(!ExtHintFieldExistsL(theFS)); //The field shouldn't exist in original table

	//Contact model must open and upgrade database
	test.Printf(_L("Loading cntmodel\n"));
	CContactDatabase* theDatabase = NULL; 
	
	TestTrap(theDatabase = CContactDatabase::OpenL(KDatabaseSecureName));
	delete theDatabase;
	theDatabase = NULL;

	//Copy the file to the C drive, where it can be checked by the test code through DBMS
	serv.CopyFileL(KDatabaseSecurePhysicalName, KDatabaseFileName);

	test.Printf(_L("Checking ExtHintField after opening with cntmodel\n"));
	TestTrue(ExtHintFieldExistsL(theFS)); //Contacts model must have created the ExtHintField
	test.End();
	}
Beispiel #2
0
bool MockOLED::drawGeneralMock(String stringToPrint,MockOLED& obj) {
	const char* conversion;
    conversion = stringToPrint.c_str();
	bool printed = obj.MockPrintToOLED (conversion); //There's an interior method here that interacts with the OLED directly and that needed to be changed
	TestTrue ("The ticket type display on the OLED", printed);
	return true; //if done
}
bool FCircularQueueTest::RunTest( const FString& Parameters )
{
	const uint32 QueueSize = 8;

	// empty queue
	{
		TCircularQueue<int32> Queue(QueueSize);

		TestTrue(TEXT("Newly created queues must be empty"), Queue.IsEmpty());
		TestFalse(TEXT("Newly created queues must not be full"), Queue.IsFull());
	}

	// partially filled
	{
		TCircularQueue<int32> Queue(QueueSize);
		int32 Value;
	
		TestTrue(TEXT("Adding to an empty queue must succeed"), Queue.Enqueue(666));
		TestFalse(TEXT("Partially filled queues must not be empty"), Queue.IsEmpty());
		TestFalse(TEXT("Partially filled queues must not be full"), Queue.IsFull());
		TestTrue(TEXT("Peeking at a partially filled queue must succeed"), Queue.Peek(Value));
	}

	// full queue
	{
		TCircularQueue<int32> Queue(QueueSize);

		for (int32 Index = 0; Index < QueueSize - 1; ++Index)
		{
			TestTrue(TEXT("Adding to non-full queue must succeed"), Queue.Enqueue(Index));
		}

		TestFalse(TEXT("Full queues must not be empty"), Queue.IsEmpty());
		TestTrue(TEXT("Full queues must be full"), Queue.IsFull());
		TestFalse(TEXT("Adding to full queue must fail"), Queue.Enqueue(666));

		int32 Value;

		for (int32 Index = 0; Index < QueueSize - 1; ++Index)
		{
			TestTrue(TEXT("Peeking at a none-empty queue must succeed"), Queue.Peek(Value));
			TestEqual(TEXT("The peeked at value must be correct"), Value, Index);
			TestTrue(TEXT("Removing from a non-empty queue must succeed"), Queue.Dequeue(Value));
			TestEqual(TEXT("The removed value must be correct"), Value, Index);
		}

		TestTrue(TEXT("A queue that had all items removed must be empty"), Queue.IsEmpty());
		TestFalse(TEXT("A queue that had all items removed must not be full"), Queue.IsFull());
	}

	return true;
}
Beispiel #4
0
bool FTimespanTest::RunTest( const FString& Parameters )
{
	// constructors must create equal objects
	FTimespan ts1_1 = FTimespan(3, 2, 1);
	FTimespan ts1_2 = FTimespan(0, 3, 2, 1);
	FTimespan ts1_3 = FTimespan(0, 3, 2, 1, 0);

	TestEqual(TEXT("Constructors must create equal objects (Hours/Minutes/Seconds vs. Days/Hours/Minutes/Seconds)"), ts1_1, ts1_2);
	TestEqual(TEXT("Constructors must create equal objects (Hours/Minutes/Seconds vs. Days/Hours/Minutes/Seconds/Milliseconds)"), ts1_1, ts1_3);

	// component getters must return correct values
	FTimespan ts2_1 = FTimespan(1, 2, 3, 4, 5);

	TestEqual(TEXT("Component getters must return correct values (Days)"), ts2_1.GetDays(), 1);
	TestEqual(TEXT("Component getters must return correct values (Hours)"), ts2_1.GetHours(), 2);
	TestEqual(TEXT("Component getters must return correct values (Minutes)"), ts2_1.GetMinutes(), 3);
	TestEqual(TEXT("Component getters must return correct values (Seconds)"), ts2_1.GetSeconds(), 4);
	TestEqual(TEXT("Component getters must return correct values (Milliseconds)"), ts2_1.GetMilliseconds(), 5);

	// durations of positive and negative time spans must match
	FTimespan ts3_1 = FTimespan(1, 2, 3, 4, 5);
	FTimespan ts3_2 = FTimespan(-1, -2, -3, -4, -5);

	TestEqual(TEXT("Durations of positive and negative time spans must match"), ts3_1.GetDuration(), ts3_2.GetDuration());

	// static constructors must create correct values
	TestEqual(TEXT("Static constructors must create correct values (FromDays)"), FTimespan::FromDays(123).GetTotalDays(), 123.0);
	TestEqual(TEXT("Static constructors must create correct values (FromHours)"), FTimespan::FromHours(123).GetTotalHours(), 123.0);
	TestEqual(TEXT("Static constructors must create correct values (FromMinutes)"), FTimespan::FromMinutes(123).GetTotalMinutes(), 123.0);
	TestEqual(TEXT("Static constructors must create correct values (FromSeconds)"), FTimespan::FromSeconds(123).GetTotalSeconds(), 123.0);
	TestEqual(TEXT("Static constructors must create correct values (FromMilliseconds)"), FTimespan::FromMilliseconds(123).GetTotalMilliseconds(), 123.0);

	// string conversions must return correct strings
	FTimespan ts5_1 = FTimespan(1, 2, 3, 4, 5);

	TestEqual<FString>(TEXT("String conversion (Default)"), ts5_1.ToString(), TEXT("1.02:03:04.005"));
	TestEqual<FString>(TEXT("String conversion (%n%d.%h:%m:%s.%f)"), ts5_1.ToString(TEXT("%n%d.%h:%m:%s.%f")), TEXT("1.02:03:04.005"));

	// parsing valid strings must succeed
	FTimespan ts6_1 = FTimespan(1, 2, 3, 4, 5);
	FTimespan ts6_2;

	TestTrue(TEXT("Parsing valid strings must succeed (1.02:03:04.005)"), FTimespan::Parse(TEXT("1.02:03:04.005"), ts6_2));
	TestEqual(TEXT("Parsing valid strings must result in correct values (1.02:03:04.005)"), ts6_2, ts6_1);

	// parsing invalid strings must fail
	FTimespan ts7_1;

	//TestFalse(TEXT("Parsing invalid strings must fail (1,02:03:04.005)"), FTimespan::Parse(TEXT("1,02:03:04.005"), ts7_1));
	//TestFalse(TEXT("Parsing invalid strings must fail (1.1.02:03:04:005)"), FTimespan::Parse(TEXT("1.1.02:03:04:005"), ts7_1));
	//TestFalse(TEXT("Parsing invalid strings must fail (04:005)"), FTimespan::Parse(TEXT("04:005"), ts7_1));

	return true;
}
Beispiel #5
0
void MockSDBeacon::SDBeaconSetup (MockSdFat& SD) {//Checked and good YEP
	//Serial.begin (9600);
  Serial.print(F("Initializing SD card..."));
	pinMode(10, OUTPUT);
	
  if (!SD.begin(4)) {
    Serial.println(F("initialization failed!"));
    return;
  }
  Serial.println(F("initialization done."));
	TestTrue ("The SD setup", SD.available());
}
bool FAnalyticsEventAttributeUnitTest::RunTest(const FString& Parameters)
{
	if (FEngineAnalytics::IsAvailable())
	{
		FString AttributeName;
		FString AttributeValue;

		AttributeName = "Test of";
		AttributeValue = "FAnalyticsEventAttribute '(const FString InName, const FString& InVaue)'";

		//Setup the 'Event Attributes'
		FAnalyticsEventAttribute EventAttributesFStringTest(AttributeName, AttributeValue);
		TestTrue(TEXT("Expected to take in these type of values '(const FString&, const FString&)'"), (EventAttributesFStringTest.AttrName == TEXT("Test of") && EventAttributesFStringTest.AttrValue == "FAnalyticsEventAttribute '(const FString InName, const FString& InVaue)'"));

		FAnalyticsEventAttribute EventAttributesTCHARTest(AttributeName, TEXT("FAnalyticsEventAttribute '(const FString InName, const TCHAR* InValue)'"));
		TestTrue(TEXT("Expected to take in these type of values '(const FString&, const TCHAR*')"), (EventAttributesTCHARTest.AttrName == TEXT("Test of") && EventAttributesTCHARTest.AttrValue == TEXT("FAnalyticsEventAttribute '(const FString InName, const TCHAR* InValue)'")));

		bool bIsBoolTest = true;
		FAnalyticsEventAttribute EventAttributesBoolTest(AttributeName, bIsBoolTest);
		TestTrue(TEXT("Expected to take in these types of values '(const FString&, bool)'"), (EventAttributesBoolTest.AttrName == TEXT("Test of") && EventAttributesBoolTest.AttrValue == "true"));

		FGuid GuidTest(FGuid::NewGuid());
		FAnalyticsEventAttribute EventAttributesGuidTest(AttributeName, GuidTest);
		TestTrue(TEXT("Expected to take in these type of values '(const FString&, FGuid)'"), (EventAttributesGuidTest.AttrName == TEXT("Test of") && EventAttributesGuidTest.AttrValue == GuidTest.ToString()));

		int32 InNumericType = 42;
		FAnalyticsEventAttribute EventAttributesTInValueTest(AttributeName, InNumericType);
		TestTrue(TEXT("Expected to take in a arithmetic type (example int32)"), (EventAttributesTInValueTest.AttrName == TEXT("Test of") && EventAttributesTInValueTest.AttrValue == TEXT("42")));

		TArray<int32> InNumericArray;
		InNumericArray.Add(0);
		InNumericArray.Add(1);
		InNumericArray.Add(2);
		FAnalyticsEventAttribute EventAttributesTArray(AttributeName, InNumericArray);
		TestTrue(TEXT("Expected to take in am arithmetic TArray"), (EventAttributesTArray.AttrName == TEXT("Test of") && EventAttributesTArray.AttrValue == TEXT("0,1,2")));

		FString TMapKey1 = "TestKey 1";
		FString TMapKey2 = "TestKey 2";
		FString TMapKey3 = "TestKey 3";
		int32 NumericValue1 = 0;
		int32 NumericValue2 = 1;
		int32 NumericValue3 = 99;
		TMap<FString, int32> InTMap;
		InTMap.Add(TMapKey1, NumericValue1);
		InTMap.Add(TMapKey2, NumericValue2);
		InTMap.Add(TMapKey3, NumericValue3);
		FAnalyticsEventAttribute EventAttributesTMap(AttributeName, InTMap);
		TestTrue(TEXT("Expected to take in a TMap "), (EventAttributesTMap.AttrName == TEXT("Test of") && EventAttributesTMap.AttrValue == TEXT("TestKey 1:0,TestKey 2:1,TestKey 3:99")));

		return true;
	}

	ExecutionInfo.LogItems.Add(TEXT("SKIPPED 'FAnalyticsEventAttributeUnitTest' test.  EngineAnalytics are not currently available."));
	return true;
}
bool FLightingPromotionPointLightPlaceRotScaleTest::RunTest(const FString& Parameters)
{
	//** SETUP **//
	// Create the world.
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Test Summary
	AddLogItem(TEXT("Place, Scale, and Rotate.\n- A Point light is placed into the world.\n- The light is moved.\n- The light is rotated.\n- The light is scaled up."));

	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		APointLight* PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), FTransform()));
		// Set the actors location, rotation, and scale3D.
		PointLight->SetActorLocation(POINT_LIGHT_UPDATED_LOCATION);
		PointLight->SetActorRotation(POINT_LIGHT_UPDATED_ROTATION);
		PointLight->SetActorScale3D(POINT_LIGHT_UPDATED_SCALE3D);

		//** VERIFY **//
		FVector CurrentLocation;
		LightingTestHelpers::GetActorCurrentLocation(CurrentLevel, PointLight->GetName(), CurrentLocation);
		FRotator CurrentRotation;
		LightingTestHelpers::GetActorCurrentRotation(CurrentLevel, PointLight->GetName(), CurrentRotation);
		FVector CurrentScale3D;
		LightingTestHelpers::GetActorCurrentScale3D(CurrentLevel, PointLight->GetName(), CurrentScale3D);
		bool RotationsAreEqual = CurrentRotation.Equals(POINT_LIGHT_UPDATED_ROTATION, 1);

		TestTrue(TEXT("The placed point light was not found."), LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, PointLight->GetName(), PointLight->GetClass()));
		TestEqual<FVector>(TEXT("The point light is not in correct location"), POINT_LIGHT_UPDATED_LOCATION, CurrentLocation);
		TestTrue(TEXT("The point light is not rotated correctly."), RotationsAreEqual);
		TestEqual<FVector>(TEXT("The point light is not scaled correctly."), POINT_LIGHT_UPDATED_SCALE3D, CurrentScale3D);

		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
Beispiel #8
0
void MockSDBeacon::simpleReadSD (String fileName, MockSdFat& SD, MockFile& myFile){ //No way to sensibly shorten
	const char* conversion = fileName.c_str();
	//myFile = SD.open(conversion, FILE_READ);
	if (myFile.available()) {
	  while (bool success = myFile.available()) {
	    Serial.write(myFile.read());
			TestTrue ("simpleRead", success);
			break;
	  }
	  myFile.close();
	} 
	else 
	{
	    Serial.print(F("Error opening "));
			Serial.println (fileName);
	 }
}
bool FViewportShowflagsToggleOnTest::RunTest( const FString& Parameters )
{
	// SETUP //	
	// Get the index for the flag and convert it back to an int.
	int32 FlagIndex = FCString::Atoi( *Parameters );
	int32 ViewportClientNumber = 0;
	bool OrigianlShowFlagState = FViewportTestHelper::GetPerspectiveOriginalFlagstate( FlagIndex, ViewportClientNumber );
	FLevelEditorViewportClient* ViewportClient = GEditor->LevelViewportClients[ViewportClientNumber];

	// TEST //
	// Set the show flag to be enabled.
	ViewportClient->EngineShowFlags.SetSingleFlag(FlagIndex, true);

	// VERIFY //
	bool NewFlagState = ViewportClient->EngineShowFlags.GetSingleFlag(FlagIndex);
	TestTrue(TEXT("The showflag state was not set to true."), NewFlagState);

	// TEARDOWN //
	// This sets the view port back to it's default show flag value.
	ViewportClient->EngineShowFlags.SetSingleFlag(FlagIndex, OrigianlShowFlagState);

	return true;
}
bool FLightPointLightPlacement::RunTest(const FString& Parameters)
{
	//** SETUP **//
	// Create a new level.
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Light Setup
	APointLight* PointLight = nullptr;
	const FTransform Transform;
	
	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), Transform));

		//** VERIFY **//
		TestTrue(TEXT("The placed point light was not found."), LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, PointLight->GetName(), PointLight->GetClass()));
		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
Beispiel #11
0
bool MockSDBeacon::searchDatabaseForTicket(String TicketString, MockSdFat& SD, MockFile& myFile){ //No way to sensibly shorten
		const char* TicketNo = TicketString.c_str();
		bool report = false;
		//Serial.println (TicketNo);
		//myFile = SD.open("test.txt");  
		if (myFile.available()) {
			const char* buf;
    	const char* reader = myFile.read(buf, 16); //couldn't quite get this to work properly--still working on it
    	if (strncmp(reader, TicketNo, 14) == 0)
    	{
      	//Serial.println(F("Match!"));
				report = true; 
      }
     	else {
				Serial.println ("No Match");
    	}
    myFile.close();
		TestTrue ("Database search", report);
		return report;
  }
	else {
	Serial.println(F("error opening file")); //error
  }
}
Beispiel #12
0
void MockBLE::TflyBLESetup(){  //Use only in the setup loop  YEP
  ble_set_name ("TFLY");
  ble_begin ();
  //Serial.begin (57600);
  TestTrue ("The ble setup", true);
}
Beispiel #13
0
void MockOLED::drawSetupMock(MockOLED& obj) {
	//Serial.begin (9600); //alternately comment out if using more than one setup function
	TestTrue ("The OLED is setup", obj.exists);
	bool printed = obj.MockPrintToOLED ("Setting Up"); //There's an interior method here that interacts with the OLED
	TestTrue ("drawSetup Print Check", printed);
}
Beispiel #14
0
void MockSDBeacon::fileRemove (String fileName, MockSdFat& SD, MockFile& myFile) {
	const char* conversion = fileName.c_str();
   SD.open(conversion);
	TestTrue ("fileremove", SD.remove(conversion));
}
Beispiel #15
0
bool FIPv4AddressTest::RunTest( const FString& Parameters )
{
	// component access must be correct
	FIPv4Address a1_1 = FIPv4Address(1, 2, 3, 4);

	TestEqual<uint8>(TEXT("Byte 0 of 1.2.3.4 must be 4"), a1_1.GetByte(0), 4);
	TestEqual<uint8>(TEXT("Byte 1 of 1.2.3.4 must be 3"), a1_1.GetByte(1), 3);
	TestEqual<uint8>(TEXT("Byte 2 of 1.2.3.4 must be 2"), a1_1.GetByte(2), 2);
	TestEqual<uint8>(TEXT("Byte 3 of 1.2.3.4 must be 1"), a1_1.GetByte(3), 1);

	// link local addresses must be recognized
	FIPv4Address a2_1 = FIPv4Address(169, 254, 0, 1);
	FIPv4Address a2_2 = FIPv4Address(168, 254, 0, 1);
	FIPv4Address a2_3 = FIPv4Address(169, 253, 0, 1);

	TestTrue(TEXT("169.254.0.1 must be a link local address"), a2_1.IsLinkLocal());
	TestFalse(TEXT("168.254.0.1 must not be a link local address"), a2_2.IsLinkLocal());
	TestFalse(TEXT("169.253.0.1 must not be a link local address"), a2_3.IsLinkLocal());

	// loopback addresses must be recognized
	FIPv4Address a3_1 = FIPv4Address(127, 0, 0, 1);
	FIPv4Address a3_2 = FIPv4Address(128, 0, 0, 1);

	TestTrue(TEXT("127.0.0.1 must be a loopback address"), a3_1.IsLoopbackAddress());
	TestFalse(TEXT("128.0.0.1 must not be a loopback address"), a3_2.IsLoopbackAddress());

	// multicast addresses must be recognized
	FIPv4Address a4_1 = FIPv4Address(223, 255, 255, 255);
	FIPv4Address a4_2 = FIPv4Address(224, 0, 0, 0);
	FIPv4Address a4_3 = FIPv4Address(239, 255, 255, 255);
	FIPv4Address a4_4 = FIPv4Address(240, 0, 0, 0);

	TestFalse(TEXT("223.255.255.255 must not be a multicast address"), a4_1.IsMulticastAddress());
	TestTrue(TEXT("224.0.0.0 must be a multicast address"), a4_2.IsMulticastAddress());
	TestTrue(TEXT("239.255.255.255 must be a multicast address"), a4_3.IsMulticastAddress());
	TestFalse(TEXT("240.0.0.0 must not be a multicast address"), a4_4.IsMulticastAddress());

	// string conversion
	FIPv4Address a5_1 = FIPv4Address(1, 2, 3, 4);

	TestEqual<FString>(TEXT("String conversion (1.2.3.4)"), a5_1.ToText().ToString(), TEXT("1.2.3.4"));

	// parsing valid strings must succeed
	FIPv4Address a6_1 = FIPv4Address(1, 2, 3, 4);
	FIPv4Address a6_2;

	TestTrue(TEXT("Parsing valid strings must succeed (1.2.3.4)"), FIPv4Address::Parse(TEXT("1.2.3.4"), a6_2));
	TestEqual(TEXT("Parsing valid strings must result in correct value (1.2.3.4)"), a6_2, a6_1);

	// parsing invalid strings must fail
	FIPv4Address a7_1;

	TestFalse(TEXT("Parsing invalid strings must fail (1.2.3)"), FIPv4Address::Parse(TEXT("1.2.3"), a6_2));

	// site local addresses must be recognized
	FIPv4Address a8_1 = FIPv4Address(10, 0, 0, 1);
	FIPv4Address a8_2 = FIPv4Address(172, 16, 0, 1);
	FIPv4Address a8_3 = FIPv4Address(192, 168, 0, 1);

	TestTrue(TEXT("10.0.0.1 must be a site local address"), a8_1.IsSiteLocalAddress());
	TestTrue(TEXT("172.16.0.1 must be a site local address"), a8_2.IsSiteLocalAddress());
	TestTrue(TEXT("192.168.0.1 must be a site local address"), a8_3.IsSiteLocalAddress());

	FIPv4Address a8_4 = FIPv4Address(11, 0, 0, 1);
	FIPv4Address a8_5 = FIPv4Address(173, 16, 0, 1);
	FIPv4Address a8_6 = FIPv4Address(172, 17, 0, 1);
	FIPv4Address a8_7 = FIPv4Address(193, 168, 0, 1);
	FIPv4Address a8_8 = FIPv4Address(192, 169, 0, 1);

	TestFalse(TEXT("11.0.0.1 must not be a site local address"), a8_4.IsSiteLocalAddress());
	TestFalse(TEXT("173.16.0.1 must not be a site local address"), a8_5.IsSiteLocalAddress());
	TestFalse(TEXT("172.17.0.1 must not be a site local address"), a8_6.IsSiteLocalAddress());
	TestFalse(TEXT("193.168.0.1 must not be a site local address"), a8_7.IsSiteLocalAddress());
	TestFalse(TEXT("192.169.0.1 must not be a site local address"), a8_8.IsSiteLocalAddress());

	return true;
}
/** 
 * Perform some collision sweep tests. Creates a given shape mesh and checks collision normal against a collision shape type.
 * Data for tests is in the [/Script/UnrealEd.CollisionAutomationTestConfigData] section of BaseEditor.ini
 *
 * @param Parameters - Unused for this test
 * @return	TRUE if the test was successful, FALSE otherwise
 */
bool FComponentSweepMultiTest::RunTest(const FString& Parameters)
{	
	CollisionAutomationTests::TestBase = this;
	// Create map
	UWorld* World = FAutomationEditorCommonUtils::CreateNewMap();
	TestNotNull( TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World );

	static FName TraceIdent = FName(TEXT("TestTrace"));
	
	FVector StartPos;
	FVector EndPos;
	ECollisionChannel Channel = ECC_WorldStatic;
	
	UCollisionAutomationTestConfigData* Data = UCollisionAutomationTestConfigData::StaticClass()->GetDefaultObject<UCollisionAutomationTestConfigData>();
	
	// Get the tests
	for (int32 iTest = 0; iTest < Data->ComponentSweepMultiTests.Num(); iTest++)
	{
		FCollisionTestEntry OneElement = Data->ComponentSweepMultiTests[iTest];

		// Create the Actor to check against
		AStaticMeshActor* TestRayMeshActor = CollisionAutomationTests::CreateShapeMeshActor( *OneElement.RootShapeAsset, OneElement.HitResult.TraceEnd);
		// Create the collision component
		AActor* TestRayCollisionActor = CollisionAutomationTests::CreateCollisionShape( World, OneElement.ShapeType, OneElement.HitResult.TraceStart);
		
		if ((TestRayMeshActor != nullptr) && (TestRayCollisionActor != nullptr))
		{			
			// Set the collision profile and enable collision and physics
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("BlockAll"));
			TestRayMeshActor->SetActorEnableCollision(true);
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.bSimulatePhysics = true;
			UShapeComponent* CollisionComponent = Cast<UShapeComponent>(TestRayCollisionActor->GetRootComponent());
			TestRayCollisionActor->SetActorEnableCollision(true);
			if( CollisionComponent != nullptr )
			{
				CollisionComponent->SetCollisionProfileName(TEXT("BlockAll"));
				CollisionComponent->SetSimulatePhysics(true);
			}
			
			// Setup positions
			StartPos = TestRayCollisionActor->GetActorLocation();
			EndPos = TestRayMeshActor->GetActorLocation();
			// Setup the query
			FComponentQueryParams ShapeQueryParameters(TraceIdent, nullptr);
			ShapeQueryParameters.bTraceComplex = true;
			ShapeQueryParameters.bTraceAsyncScene = true;

			// Perform test
			TArray<FHitResult> OutHits;
			bool WasBlocked = World->ComponentSweepMulti(OutHits, CollisionComponent, StartPos, EndPos, FRotator::ZeroRotator, ShapeQueryParameters);
			bool BlockedBySpecified = false;
			if (WasBlocked == true)
			{
				for (int32 iHits = 0; iHits < OutHits.Num(); iHits++)
				{
					AActor* EachActor = OutHits[iHits].GetActor();
					if (EachActor == TestRayMeshActor)
					{
						BlockedBySpecified = true;	
						// This generates a snippet you can copy/paste into the ini file for test validation
						//UE_LOG(CollisionAutomationTestLog, Log, TEXT("%d:HitResult=(%s)"), iTest+1, *(CollisionAutomationTests::HitToString(OutHits[iHits])));

						CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactNormal, OneElement.HitResult.ImpactNormal, TEXT("ComponentSweepMulti"), TEXT("ImpactNormal"), iTest );
						CollisionAutomationTests::CheckVector( OutHits[iHits].Normal, OneElement.HitResult.Normal, TEXT("ComponentSweepMulti"), TEXT("Normal"), iTest );
						CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactPoint, OneElement.HitResult.ImpactPoint, TEXT("ComponentSweepMulti"), TEXT("ImpactPoint"), iTest );
						CollisionAutomationTests::CheckFloat( OutHits[iHits].Time, OneElement.HitResult.Time, TEXT("ComponentSweepMulti"), TEXT("Time"), iTest );
					}
				}
			}
			TestTrue(FString::Printf(TEXT("Test %d:ComponentSweepMulti from %s to %s failed. Should return blocking hit"), iTest+1, *TestRayMeshActor->GetName(), *TestRayCollisionActor->GetName()), BlockedBySpecified);
		}
		// Remove the actors
		TestRayMeshActor->Destroy();
		TestRayCollisionActor->Destroy();
	}

	return true;
}
Beispiel #17
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;
}
Beispiel #18
0
bool FLocItemTest::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 FLocItem
	{
		FLocItem LocItemA( TEXT("TextA") );
		LocItemA.MetadataObj = MakeShareable( new FLocMetadataObject(*SourceMetadataA) );

		FLocItem LocItemB( TEXT("TextB") );
		LocItemB.MetadataObj = MakeShareable( new FLocMetadataObject(*SourceMetadataB) );

		// Test copy ctor
		{
			FLocItem LocItemAClone = LocItemA;

			if( LocItemAClone.MetadataObj == LocItemA.MetadataObj )
			{
				AddError(TEXT("FLocItem MetadataObj and its Clone are not unique objects."));
			}

			TestEqual( TEXT("LocItemAClone.Text == LocItemA.Text"), LocItemAClone.Text, LocItemA.Text );
			TestTrue( TEXT("LocItemAClone.MetadataObj == LocItemA.MetadataObj"), *(LocItemAClone.MetadataObj) == *(LocItemA.MetadataObj) );

			TestEqual( TEXT("LocItemAClone == LocItemA"), LocItemAClone, LocItemA );
			TestFalse( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );

		}

		// Test assignment operator
		{
			FLocItem LocItemAClone( TEXT("New") );

			LocItemAClone = LocItemA;

			if( LocItemAClone.MetadataObj == LocItemA.MetadataObj )
			{
				AddError(TEXT("FLocItem MetadataObj and its Clone are not unique objects."));
			}

			TestEqual( TEXT("LocItemAClone.Text == LocItemA.Text"), LocItemAClone.Text, LocItemA.Text );
			TestTrue( TEXT("LocItemAClone.MetadataObj == LocItemA.MetadataObj"), *(LocItemAClone.MetadataObj) == *(LocItemA.MetadataObj) );

			TestEqual( TEXT("LocItemAClone == LocItemA"), LocItemAClone, LocItemA );
			TestFalse( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );
			TestFalse( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );
		}

		// Test comparison operator
		{
			// Text and MetadataObj members should both be taken into account when comparing.  Note, Metadata supports a special * name prefix that causes the type 
			//   and value of the metadata to be ignored when performing comparisons
			FLocItem LocItemAClone = LocItemA;
			TestEqual( TEXT("LocItemAClone == LocItemA"), LocItemAClone, LocItemA );

			// Metadata with * prefix does not impact comparison but both FLocItems need a metadata where the name matches( type and value can be different )
			FLocItem LocItemAClone2 = LocItemA;
			LocItemAClone.MetadataObj->SetStringField( TEXT("*NewNonCompare"), TEXT("NewNonCompareValue") );
			TestNotEqual( TEXT("LocItemAClone != LocItemAClone2"), LocItemAClone, LocItemAClone2 );

			LocItemAClone2.MetadataObj->SetStringField( TEXT("*NewNonCompare"), TEXT("NewNonCompareValue2") );
			TestEqual( TEXT("LocItemAClone == LocItemAClone2"), LocItemAClone, LocItemAClone2 );

			// Changing the text in any way will cause comparison to fail
			LocItemAClone = LocItemA;
			LocItemAClone.Text = LocItemAClone.Text + TEXT("New");
			TestNotEqual( TEXT("LocItemAClone != LocItemA"), LocItemAClone, LocItemA );

			// LocItem with valid but empty KeyMetadataObject should be equivalent to LocItem with null KeyMetadataObject
			FLocItem LocItemEmptyA(TEXT("TestText"));
			FLocItem LocItemEmptyB(TEXT("TestText"));
			LocItemEmptyB.MetadataObj = MakeShareable( new FLocMetadataObject );
			TestEqual( TEXT("LocItemEmptyA == LocItemEmptyB"), LocItemEmptyA, LocItemEmptyB );
		}

		// Testing less than operator
		{
			TestTrue( TEXT("LocItemA < LocItemB"), LocItemA < LocItemB );
			TestFalse( TEXT("LocItemB < LocItemA"), LocItemB < LocItemA );

			FLocItem LocItemAClone = LocItemA;

			// Differences in Text
			TestFalse( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );
			LocItemAClone.Text = LocItemAClone.Text + TEXT("A");
			TestFalse( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );
			//currently failing TestTrue( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );

			// Adding new key metadata entry
			LocItemAClone = LocItemA;
			LocItemAClone.MetadataObj->SetStringField( TEXT("ANewKey"), TEXT("ANewValue") );
			//currently failing TestTrue( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );
			TestFalse( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );

			// Removing a key metadata entry
			LocItemAClone = LocItemA;
			LocItemAClone.MetadataObj->RemoveField( TEXT("*IsMature") );
			TestTrue( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );
			TestFalse( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );

			// Changing a key metadata entry value
			LocItemAClone = LocItemA;
			LocItemAClone.MetadataObj->SetBoolField( TEXT("*IsMature"),true );
			//currently failing TestTrue( TEXT("LocItemA < LocItemAClone"), LocItemA < LocItemAClone );
			TestFalse( TEXT("LocItemAClone < LocItemA"), LocItemAClone < LocItemA );

			// Test null and non-null but empty Metadata
			FLocItem LocItemEmptyA( TEXT("SameText") );
			FLocItem LocItemEmptyB( TEXT("SameText") );
			TestFalse( TEXT("LocItemEmptyA < LocItemEmptyB"), LocItemEmptyA < LocItemEmptyB );
			LocItemEmptyB.MetadataObj = MakeShareable( new FLocMetadataObject );
			TestFalse( TEXT("LocItemEmptyA < LocItemEmptyB"), LocItemEmptyA < LocItemEmptyB );
			TestFalse( TEXT("LocItemEmptyB < LocItemEmptyA"), LocItemEmptyB < LocItemEmptyA );
			LocItemEmptyB.MetadataObj->SetStringField(TEXT("AMetadataKey"), TEXT("AMetadataValue"));
			TestTrue( TEXT("LocItemEmptyA < LocItemEmptyB"), LocItemEmptyA < LocItemEmptyB );
		}
	}
	return true;
}
Beispiel #19
0
bool FLocContextTest::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 FContext
	{
		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) );


		// Test copy ctor
		{
			FContext ContextAClone = ContextA;

			if( ContextAClone.InfoMetadataObj == ContextA.InfoMetadataObj )
			{
				AddError(TEXT("FContext InfoMetadataObj and its Clone are not unique objects."));
			}

			if( ContextAClone.KeyMetadataObj == ContextA.KeyMetadataObj )
			{
				AddError(TEXT("FContext KeyMetadataObj and its Clone are not unique objects."));
			}

			TestEqual( TEXT("ContextAClone.Key == ContextA.Key"), ContextAClone.Key, ContextA.Key );
			TestEqual( TEXT("ContextAClone.SourceLocation == ContextA.SourceLocation"), ContextAClone.SourceLocation, ContextA.SourceLocation );
			TestEqual( TEXT("ContextAClone.bIsOptional == ContextA.bIsOptional"), ContextAClone.bIsOptional, ContextA.bIsOptional );
			TestTrue( TEXT("ContextAClone.InfoMetadataObj == ContextA.InfoMetadataObj"), *(ContextAClone.InfoMetadataObj) == *(ContextA.InfoMetadataObj) );
			TestTrue( TEXT("ContextAClone.KeyMetadataObj == ContextA.KeyMetadataObj"), *(ContextAClone.KeyMetadataObj) == *(ContextA.KeyMetadataObj) );

			TestEqual( TEXT("ContextAClone == ContextA"), ContextAClone, ContextA );
			TestFalse( TEXT("ContextAClone < ContextA"), ContextAClone < ContextA );

		}

		// Test assignment operator
		{
			FContext ContextAClone;
			ContextAClone = ContextA;

			if( ContextAClone.InfoMetadataObj == ContextA.InfoMetadataObj )
			{
				AddError(TEXT("FContext InfoMetadataObj and its Clone are not unique objects."));
			}

			if( ContextAClone.KeyMetadataObj == ContextA.KeyMetadataObj )
			{
				AddError(TEXT("FContext KeyMetadataObj and its Clone are not unique objects."));
			}

			TestEqual( TEXT("ContextAClone.Key == ContextA.Key"), ContextAClone.Key, ContextA.Key );
			TestEqual( TEXT("ContextAClone.SourceLocation == ContextA.SourceLocation"), ContextAClone.SourceLocation, ContextA.SourceLocation );
			TestEqual( TEXT("ContextAClone.bIsOptional == ContextA.bIsOptional"), ContextAClone.bIsOptional, ContextA.bIsOptional );
			TestTrue( TEXT("ContextAClone.InfoMetadataObj == ContextA.InfoMetadataObj"), *(ContextAClone.InfoMetadataObj) == *(ContextA.InfoMetadataObj) );
			TestTrue( TEXT("ContextAClone.KeyMetadataObj == ContextA.KeyMetadataObj"), *(ContextAClone.KeyMetadataObj) == *(ContextA.KeyMetadataObj) );

			TestEqual( TEXT("ContextAClone == ContextA"), ContextAClone, ContextA );
			TestFalse( TEXT("ContextAClone < ContextA"), ContextAClone < ContextA );
		}

		// Test comparison operator
		{
			// Key and KeyMetadataObj members should be the only items that are taken into account when comparing
			FContext ContextAClone = ContextA;
			TestEqual( TEXT("ContextAClone == ContextA"), ContextAClone, ContextA );

			// Arbitrarily change all the non-important members
			ContextAClone.SourceLocation = ContextA.SourceLocation + TEXT("New");
			ContextAClone.bIsOptional = !ContextA.bIsOptional;
			ContextAClone.InfoMetadataObj.Reset();
			ContextAClone.InfoMetadataObj = MakeShareable( new FLocMetadataObject( *InfoMetadataB ) );
			TestEqual( TEXT("ContextAClone == ContextA"), ContextAClone, ContextA );

			// Changing the key in any way will cause comparison to fail
			ContextAClone.Key = ContextAClone.Key + TEXT("New");
			TestNotEqual( TEXT("ContextAClone != ContextA"), ContextAClone, ContextA );

			// Reset and test KeyMetadataObj change to one of the value entries
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->SetStringField( TEXT("TargetPlurality"), TEXT("Plural") );
			TestNotEqual( TEXT("ContextAClone != ContextA"), ContextAClone, ContextA );

			// Reset and test addition of entry to KeyMetadataObj
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->SetStringField( TEXT("NewField"), TEXT("NewFieldValue") );
			TestNotEqual( TEXT("ContextAClone != ContextA"), ContextAClone, ContextA );

			// Reset and test removal of entry from KeyMetadataObj
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->RemoveField( TEXT("TargetPlurality") );
			TestNotEqual( TEXT("ContextAClone != ContextA"), ContextAClone, ContextA );

			// Context with valid but empty KeyMetadataObject should be equivalent to Context with null KeyMetadataObject
			FContext ContextEmptyA;
			FContext ContextEmptyB;
			ContextEmptyB.KeyMetadataObj = MakeShareable( new FLocMetadataObject );
			TestEqual( TEXT("ContextEmptyA == ContextEmptyB"), ContextEmptyA, ContextEmptyB );
		}

		// Testing less than operator
		{
			TestTrue( TEXT("ContextA < ContextB"), ContextA < ContextB );

			FContext ContextAClone = ContextA;

			// Differences in Key
			TestFalse( TEXT("ContextA < ContextAClone"), ContextA < ContextAClone );
			ContextAClone.Key = ContextAClone.Key + TEXT("A");
			//currently failing TestTrue( TEXT("ContextA < ContextAClone"), ContextA < ContextAClone );

			// Adding new key metadata entry that will appear before other entries
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->SetStringField( TEXT("ANewKey"), TEXT("ANewValue") );
			TestTrue( TEXT("ContextAClone < ContextA"), ContextAClone < ContextA );

			// Adding new key metadata entry that will appear after other entries
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->SetStringField( TEXT("ZNewKey"), TEXT("ZNewValue") );
			//currently failing TestTrue( TEXT("ContextA < ContextAClone"), ContextA < ContextAClone );

			// Removing a key metadata entry
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->RemoveField( TEXT("TargetPlurality") ) ;
			TestTrue( TEXT("ContextAClone < ContextA"), ContextAClone < ContextA );

			// Changing a key metadata entry value
			ContextAClone = ContextA;
			ContextAClone.KeyMetadataObj->SetStringField( TEXT("TargetPlurality"), TEXT("A") ) ;
			TestTrue( TEXT("ContextAClone < ContextA"), ContextAClone < ContextA );

			FContext ContextEmptyA;
			FContext ContextEmptyB;
			TestFalse( TEXT("ContextEmptyA < ContextEmptyB"), ContextEmptyA < ContextEmptyB );
			ContextEmptyB.KeyMetadataObj = MakeShareable( new FLocMetadataObject );
			TestFalse( TEXT("ContextEmptyA < ContextEmptyB"), ContextEmptyA < ContextEmptyB );
			TestFalse( TEXT("ContextEmptyB < ContextEmptyA"), ContextEmptyB < ContextEmptyA );
			ContextEmptyB.KeyMetadataObj->SetStringField(TEXT("AMetadataKey"), TEXT("AMetadataValue"));
			TestTrue( TEXT("ContextEmptyA < ContextEmptyB"), ContextEmptyA < ContextEmptyB );
		}
	}
	return true;
}
bool FGuidTest::RunTest( const FString& Parameters )
{
	FGuid g = FGuid(305419896, 2271560481, 305419896, 2271560481);

	// string conversions
	TestEqual(TEXT("String conversion (Default) must return EGuidFormats::Digits string"), g.ToString(), g.ToString(EGuidFormats::Digits));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::Digits)"), g.ToString(EGuidFormats::Digits), TEXT("12345678876543211234567887654321"));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::DigitsWithHyphens)"), g.ToString(EGuidFormats::DigitsWithHyphens), TEXT("12345678-8765-4321-1234-567887654321"));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::DigitsWithHyphensInBraces)"), g.ToString(EGuidFormats::DigitsWithHyphensInBraces), TEXT("{12345678-8765-4321-1234-567887654321}"));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::DigitsWithHyphensInParentheses)"), g.ToString(EGuidFormats::DigitsWithHyphensInParentheses), TEXT("(12345678-8765-4321-1234-567887654321)"));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::HexValuesInBraces)"), g.ToString(EGuidFormats::HexValuesInBraces), TEXT("{0x12345678,0x8765,0x4321,{0x12,0x34,0x56,0x78,0x87,0x65,0x43,0x21}}"));
	TestEqual<FString>(TEXT("String conversion (EGuidFormats::UniqueObjectGuid)"), g.ToString(EGuidFormats::UniqueObjectGuid), TEXT("12345678-87654321-12345678-87654321"));

	// parsing valid strings (exact)
	FGuid g2_1;

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::Digits)"), FGuid::ParseExact(TEXT("12345678876543211234567887654321"), EGuidFormats::Digits, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::Digits)"), g2_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphens)"), FGuid::ParseExact(TEXT("12345678-8765-4321-1234-567887654321"), EGuidFormats::DigitsWithHyphens, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphens)"), g2_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphensInBraces)"), FGuid::ParseExact(TEXT("{12345678-8765-4321-1234-567887654321}"), EGuidFormats::DigitsWithHyphensInBraces, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphensInBraces)"), g2_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphensInParentheses)"), FGuid::ParseExact(TEXT("(12345678-8765-4321-1234-567887654321)"), EGuidFormats::DigitsWithHyphensInParentheses, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::DigitsWithHyphensInParentheses)"), g2_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::HexValuesInBraces)"), FGuid::ParseExact(TEXT("{0x12345678,0x8765,0x4321,{0x12,0x34,0x56,0x78,0x87,0x65,0x43,0x21}}"), EGuidFormats::HexValuesInBraces, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::HexValuesInBraces)"), g2_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (EGuidFormats::UniqueObjectGuid)"), FGuid::ParseExact(TEXT("12345678-87654321-12345678-87654321"), EGuidFormats::UniqueObjectGuid, g2_1));
	TestEqual(TEXT("Parsing valid strings must succeed (EGuidFormats::UniqueObjectGuid)"), g2_1, g);

	// parsing invalid strings (exact)


	// parsing valid strings (automatic)
	FGuid g3_1;

	TestTrue(TEXT("Parsing valid strings must succeed (12345678876543211234567887654321)"), FGuid::Parse(TEXT("12345678876543211234567887654321"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed (12345678876543211234567887654321)"), g3_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (12345678-8765-4321-1234-567887654321)"), FGuid::Parse(TEXT("12345678-8765-4321-1234-567887654321"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed (12345678-8765-4321-1234-567887654321)"), g3_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed ({12345678-8765-4321-1234-567887654321})"), FGuid::Parse(TEXT("{12345678-8765-4321-1234-567887654321}"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed ({12345678-8765-4321-1234-567887654321})"), g3_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed ((12345678-8765-4321-1234-567887654321))"), FGuid::Parse(TEXT("(12345678-8765-4321-1234-567887654321)"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed ((12345678-8765-4321-1234-567887654321))"), g3_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed ({0x12345678,0x8765,0x4321,{0x12,0x34,0x56,0x78,0x87,0x65,0x43,0x21}})"), FGuid::Parse(TEXT("{0x12345678,0x8765,0x4321,{0x12,0x34,0x56,0x78,0x87,0x65,0x43,0x21}}"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed ({0x12345678,0x8765,0x4321,{0x12,0x34,0x56,0x78,0x87,0x65,0x43,0x21}})"), g3_1, g);

	TestTrue(TEXT("Parsing valid strings must succeed (12345678-87654321-12345678-87654321)"), FGuid::Parse(TEXT("12345678-87654321-12345678-87654321"), g3_1));
	TestEqual(TEXT("Parsing valid strings must succeed (12345678-87654321-12345678-87654321)"), g3_1, g);

	//parsing invalid strings (automatic)

	// GUID validation
	FGuid g4_1 = FGuid::NewGuid();

	TestTrue(TEXT("New GUIDs must be valid"), g4_1.IsValid());
	
	g4_1.Invalidate();

	TestFalse(TEXT("Invalidated GUIDs must be invalid"), g4_1.IsValid());

	return true;
}
bool FAnalyticStartUpSimTest::RunTest(const FString& Parameters)
{
	if (FEngineAnalytics::IsAvailable())
	{
		//Setup a temp AccountID.
		FGuid TempAccountID(FGuid::NewGuid());
		FString OldEpicAccountID = FPlatformMisc::GetEpicAccountId();
		FString NewEpicAccountID = TempAccountID.ToString().ToLower();
		FPlatformMisc::SetEpicAccountId(NewEpicAccountID);

		//Setup the 'Event Attributes'
		TArray<FAnalyticsEventAttribute> EventAttributes;
		EventAttributes.Add(FAnalyticsEventAttribute(TEXT("MachineID"),		FPlatformMisc::GetMachineId().ToString(EGuidFormats::Digits).ToLower()));
		EventAttributes.Add(FAnalyticsEventAttribute(TEXT("AccountID"),		FPlatformMisc::GetEpicAccountId()));
		EventAttributes.Add(FAnalyticsEventAttribute(TEXT("OSID"),			FPlatformMisc::GetOperatingSystemId()));
		EventAttributes.Add(FAnalyticsEventAttribute(TEXT("GameName"),		FApp::GetGameName()));
		EventAttributes.Add(FAnalyticsEventAttribute(TEXT("CommandLine"),	FCommandLine::Get()));
		
		//Record the event with the 'Engine.AutomationTest.Analytics.ProgramStartedEvent' title
		FEngineAnalytics::GetProvider().RecordEvent(TEXT("Engine.AutomationTest.Analytics.ProgramStartedEvent"), EventAttributes);

		//Get the event strings used
		FString MachineIDTest	=	FPlatformMisc::GetMachineId().ToString(EGuidFormats::Digits).ToLower();
		FString AccountIDTest	=	FPlatformMisc::GetEpicAccountId();
		FString OSID			=	FPlatformMisc::GetOperatingSystemId();
		FString GameNameTest	=	FApp::GetGameName();
		FString CommandLineArgs	=	FCommandLine::Get();

		//Test the strings to verify they have data.
		TestFalse(TEXT("'MachineID' is not expected to be empty!"), MachineIDTest.IsEmpty());
		TestFalse(TEXT("'AccountID' is not expected to be empty!"), AccountIDTest.IsEmpty());
		TestFalse(TEXT("'OperatingSystemID' is not expected to be empty!"), OSID.IsEmpty());
		TestFalse(TEXT("'GameName' is expected."), GameNameTest.IsEmpty());


		//Verify record event is holding the actual data.  This only triggers if the command line argument of 'AnalyticsDisableCaching' was used.
		if (CommandLineArgs.Contains(TEXT("AnalyticsDisableCaching")))
		{
			FString FullMachineIDTestEventName = FString::Printf(TEXT("MachineID\":\"%s"), *MachineIDTest);
			FString FullAccountIDTestEventName = FString::Printf(TEXT("AccountID\":\"%s"), *AccountIDTest);
			FString FullOSIDTestEventName = FString::Printf(TEXT("OSID\":\"%s"), *OSID);

			for (int32 i = 0; i < ExecutionInfo.LogItems.Num(); i++)
			{
				if (ExecutionInfo.LogItems[i].Contains(TEXT("Engine.AutomationTest.Analytics.ProgramStartedEvent")))
				{
					TestTrue(TEXT("Recorded event name is expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(TEXT("Engine.AutomationTest.Analytics.ProgramStartedEvent")));
					TestTrue(TEXT("'MachineID' is expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(*FullMachineIDTestEventName));
					TestTrue(TEXT("'AccountID' is expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(*FullAccountIDTestEventName));
					TestTrue(TEXT("'OperatingSystemID' is expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(*FullOSIDTestEventName));
					TestTrue(TEXT("'GameName' is expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(*GameNameTest));
					TestTrue(TEXT("'CommandLine arguments' are expected to be in the sent event."), ExecutionInfo.LogItems[i].Contains(TEXT("AnalyticsDisableCaching")));
				}
			}
		}

		//Set the AccountID to it's original state.
		FPlatformMisc::SetEpicAccountId(OldEpicAccountID);
		return true;
	}

	ExecutionInfo.LogItems.Add(TEXT("SKIPPED 'FAnalyticStartUpSimTest' test.  EngineAnalytics are not currently available."));
	return true;	
}
bool FRangeBoundTest::RunTest( const FString& Parameters )
{
	// ensure template instantiation works
	FDateRange DateRange;
	FDoubleRange DoubleRange;
	FFloatRange FloatRange;
	FInt8Range Int8Range;
	FInt16Range Int16Range;
	FInt32Range Int32Range;
	FInt64Range Int64Range;

	// bound types must be correct after construction
	FFloatRangeBound b1_1 = FFloatRangeBound::Exclusive(2.0f);
	FFloatRangeBound b1_2 = FFloatRangeBound::Inclusive(2.0f);
	FFloatRangeBound b1_3 = FFloatRangeBound::Open();
	FFloatRangeBound b1_4 = 2;

	TestTrue(TEXT("Exclusive bound constructor must create exclusive bound"), b1_1.IsExclusive());
	TestTrue(TEXT("Exclusive bound constructor must create closed bound"), b1_1.IsClosed());
	TestFalse(TEXT("Exclusive bound constructor must not create inclusive bound"), b1_1.IsInclusive());
	TestFalse(TEXT("Exclusive bound constructor must not create open bound"), b1_1.IsOpen());
	TestEqual(TEXT("Exclusive bound constructor must create the correct value"), b1_1.GetValue(), 2.0f);

	TestTrue(TEXT("Inclusive bound constructor must create exclusive bound"), b1_2.IsInclusive());
	TestTrue(TEXT("Inclusive bound constructor must create closed bound"), b1_2.IsClosed());
	TestFalse(TEXT("Inclusive bound constructor must not create exclusive bound"), b1_2.IsExclusive());
	TestFalse(TEXT("Inclusive bound constructor must not create open bound"), b1_2.IsOpen());
	TestEqual(TEXT("Inclusive bound constructor must create the correct value"), b1_2.GetValue(), 2.0f);

	TestTrue(TEXT("Open bound constructor must create open bound"), b1_3.IsOpen());
	TestFalse(TEXT("Open bound constructor must not create closed bound"), b1_3.IsClosed());
	TestFalse(TEXT("Open bound constructor must not create exclusive bound"), b1_3.IsExclusive());
	TestFalse(TEXT("Open bound constructor must not create inclusive bound"), b1_3.IsInclusive());

	TestTrue(TEXT("Implicit constructor must create an inclusive bound"), b1_4.IsInclusive());
	TestEqual(TEXT("Implicit constructor must create the correct value"), b1_4, b1_2);

	// comparisons must be correct
	FFloatRangeBound b2_1 = FFloatRangeBound::Exclusive(2.0f);
	FFloatRangeBound b2_2 = FFloatRangeBound::Exclusive(2.0f);
	FFloatRangeBound b2_3 = FFloatRangeBound::Inclusive(2.0f);
	FFloatRangeBound b2_4 = FFloatRangeBound::Inclusive(2.0f);
	FFloatRangeBound b2_5 = FFloatRangeBound::Open();
	FFloatRangeBound b2_6 = FFloatRangeBound::Open();

	TestTrue(TEXT("Equal exclusive bounds must be equal"), b2_1 == b2_2);
	TestTrue(TEXT("Equal inclusive bounds must be equal"), b2_3 == b2_4);
	TestTrue(TEXT("Open bounds must be equal"), b2_5 == b2_6);

	TestFalse(TEXT("Equal exclusive bounds must not be unequal"), b2_1 != b2_2);
	TestFalse(TEXT("Equal inclusive bounds must not be unequal"), b2_3 != b2_4);
	TestFalse(TEXT("Open bounds must not be unequal"), b2_5 != b2_6);

	FFloatRangeBound b2_7 = FFloatRangeBound::Exclusive(3.0f);
	FFloatRangeBound b2_8 = FFloatRangeBound::Inclusive(3.0f);

	TestTrue(TEXT("Unequal exclusive bounds must be unequal"), b2_1 != b2_7);
	TestTrue(TEXT("Unequal inclusive bounds must be unequal"), b2_2 != b2_8);

	TestFalse(TEXT("Unequal exclusive bounds must not be equal"), b2_1 == b2_7);
	TestFalse(TEXT("Unequal inclusive bounds must not be equal"), b2_2 == b2_8);

	// min-max comparisons between bounds must be correct
	FFloatRangeBound b3_1 = FFloatRangeBound::Exclusive(2.0f);
	FFloatRangeBound b3_2 = FFloatRangeBound::Inclusive(2.0f);
	FFloatRangeBound b3_3 = FFloatRangeBound::Open();

	TestEqual(TEXT("'[2' must be less than '(2' <1>"), FFloatRangeBound::MinLower(b3_2, b3_1), b3_2);
	TestEqual(TEXT("'[2' must be less than '(2' <2>"), FFloatRangeBound::MinLower(b3_1, b3_2), b3_2);
	TestEqual(TEXT("Open lower bound must be less than '(2' <1>"), FFloatRangeBound::MinLower(b3_3, b3_1), b3_3);
	TestEqual(TEXT("Open lower bound must be less than '(2' <2>"), FFloatRangeBound::MinLower(b3_1, b3_3), b3_3);
	TestEqual(TEXT("Open lower bound must be less than '[2' <1>"), FFloatRangeBound::MinLower(b3_3, b3_2), b3_3);
	TestEqual(TEXT("Open lower bound must be less than '[2' <2>"), FFloatRangeBound::MinLower(b3_2, b3_3), b3_3);

	TestEqual(TEXT("'(2' must be greater than '[2' <1>"), FFloatRangeBound::MaxLower(b3_2, b3_1), b3_1);
	TestEqual(TEXT("'(2' must be greater than '[2' <2>"), FFloatRangeBound::MaxLower(b3_1, b3_2), b3_1);
	TestEqual(TEXT("'(2' must be greater than open lower bound <1>"), FFloatRangeBound::MaxLower(b3_3, b3_1), b3_1);
	TestEqual(TEXT("'(2' must be greater than open lower bound <2>"), FFloatRangeBound::MaxLower(b3_1, b3_3), b3_1);
	TestEqual(TEXT("'[2' must be greater than open lower bound <1>"), FFloatRangeBound::MaxLower(b3_3, b3_2), b3_2);
	TestEqual(TEXT("'[2' must be greater than open lower bound <2>"), FFloatRangeBound::MaxLower(b3_2, b3_3), b3_2);

	TestEqual(TEXT("'2)' must be less than '2]' <1>"), FFloatRangeBound::MinUpper(b3_2, b3_1), b3_1);
	TestEqual(TEXT("'2)' must be less than '2]' <2>"), FFloatRangeBound::MinUpper(b3_1, b3_2), b3_1);
	TestEqual(TEXT("'2)' must be less than open upper bound <1>"), FFloatRangeBound::MinUpper(b3_3, b3_1), b3_1);
	TestEqual(TEXT("'2)' must be less than open upper bound <2>"), FFloatRangeBound::MinUpper(b3_1, b3_3), b3_1);
	TestEqual(TEXT("'2]' must be less than open upper bound <1>"), FFloatRangeBound::MinUpper(b3_3, b3_2), b3_2);
	TestEqual(TEXT("'2]' must be less than open upper bound"), FFloatRangeBound::MinUpper(b3_2, b3_3), b3_2);

	TestEqual(TEXT("'2]' must be greater than '2)' <1>"), FFloatRangeBound::MaxUpper(b3_2, b3_1), b3_2);
	TestEqual(TEXT("'2]' must be greater than '2)' <2>"), FFloatRangeBound::MaxUpper(b3_1, b3_2), b3_2);
	TestEqual(TEXT("Open upper bound must be greater than '2)' <1>"), FFloatRangeBound::MaxUpper(b3_3, b3_1), b3_3);
	TestEqual(TEXT("Open upper bound must be greater than '2)' <2>"), FFloatRangeBound::MaxUpper(b3_1, b3_3), b3_3);
	TestEqual(TEXT("Open upper bound must be greater than '2]' <1>"), FFloatRangeBound::MaxUpper(b3_3, b3_2), b3_3);
	TestEqual(TEXT("Open upper bound must be greater than '2]' <2>"), FFloatRangeBound::MaxUpper(b3_2, b3_3), b3_3);

	FFloatRangeBound b4_1 = FFloatRangeBound::Exclusive(3);
	FFloatRangeBound b4_2 = FFloatRangeBound::Inclusive(3);

	TestEqual(TEXT("'(2' must be less than '[3' <1>"), FFloatRangeBound::MinLower(b3_1, b4_2), b3_1);
	TestEqual(TEXT("'(2' must be less than '[3' <2>"), FFloatRangeBound::MinLower(b4_2, b3_1), b3_1);
	TestEqual(TEXT("'[2' must be less than '[3' <1>"), FFloatRangeBound::MinLower(b3_2, b4_2), b3_2);
	TestEqual(TEXT("'[2' must be less than '[3' <2>"), FFloatRangeBound::MinLower(b4_2, b3_2), b3_2);

	TestEqual(TEXT("'[3' must be greater than '(2' <1>"), FFloatRangeBound::MaxLower(b3_1, b4_2), b4_2);
	TestEqual(TEXT("'[3' must be greater than '(2' <2>"), FFloatRangeBound::MaxLower(b4_2, b3_1), b4_2);
	TestEqual(TEXT("'[3' must be greater than '[2' <1>"), FFloatRangeBound::MaxLower(b3_2, b4_2), b4_2);
	TestEqual(TEXT("'[3' must be greater than '[2' <2>"), FFloatRangeBound::MaxLower(b4_2, b3_2), b4_2);

	return true;
}
bool FTripleBufferTest::RunTest(const FString& Parameters)
{
	// uninitialized buffer
	{
		TTripleBuffer<int32> Buffer(NoInit);

		TestFalse(TEXT("Uninitialized triple buffer must not be dirty"), Buffer.IsDirty());
	}

	// initialized buffer
	{
		TTripleBuffer<int32> Buffer(1);

		TestFalse(TEXT("Initialized triple buffer must not be dirty"), Buffer.IsDirty());
		TestEqual(TEXT("Initialized triple buffer must have correct read buffer value"), Buffer.Read(), 1);

		Buffer.SwapReadBuffers();

		TestEqual(TEXT("Initialized triple buffer must have correct temp buffer value"), Buffer.Read(), 1);

		Buffer.SwapWriteBuffers();

		TestTrue(TEXT("Write buffer swap must set dirty flag"), Buffer.IsDirty());

		Buffer.SwapReadBuffers();

		TestFalse(TEXT("Read buffer swap must clear dirty flag"), Buffer.IsDirty());
		TestEqual(TEXT("Initialized triple buffer must have correct temp buffer value"), Buffer.Read(), 1);
	}

	// pre-set buffer
	{
		int32 Array[3] = { 1, 2, 3 };
		TTripleBuffer<int32> Buffer(Array);

		int32 Read = Buffer.Read();
		TestEqual(TEXT("Pre-set triple buffer must have correct Read buffer value"), Read, 3);

		Buffer.SwapReadBuffers();

		int32 Temp = Buffer.Read();
		TestEqual(TEXT("Pre-set triple buffer must have correct Temp buffer value"), Temp, 1);

		Buffer.SwapWriteBuffers();
		Buffer.SwapReadBuffers();

		int32 Write = Buffer.Read();
		TestEqual(TEXT("Pre-set triple buffer must have correct Write buffer value"), Write, 2);
	}

	// operations
	{
		TTripleBuffer<int32> Buffer;

		for (int32 Index = 0; Index < 6; ++Index)
		{
			int32& Write = Buffer.GetWriteBuffer(); Write = Index; Buffer.SwapWriteBuffers();
			Buffer.SwapReadBuffers();
			TestEqual(*FString::Printf(TEXT("Triple buffer must read correct value (%i)"), Index), Buffer.Read(), Index);
		}

		FRandomStream Rand;
		int32 LastRead = -1;

		for (int32 Index = 0; Index < 100; ++Index)
		{
			int32 Writes = Rand.GetUnsignedInt() % 4;

			while (Writes > 0)
			{
				int32& Write = Buffer.GetWriteBuffer(); Write = Index; Buffer.SwapWriteBuffers();
				--Writes;
			}
			
			int32 Reads = Rand.GetUnsignedInt() % 4;

			while (Reads > 0)
			{
				if (!Buffer.IsDirty())
				{
					break;
				}

				Buffer.SwapReadBuffers();
				int32 Read = Buffer.Read();
				TestTrue(TEXT("Triple buffer must read in increasing order"), Read > LastRead);
				LastRead = Read;
				--Reads;
			}
		}
	}

	return true;
}
/** 
 * Perform LineTraceSingleByChannel tests. Does a ray trace from a given point to a given shape mesh and verifies blocking is correct.
 * Data for tests is in the [/Script/UnrealEd.CollisionAutomationTestConfigData] section of BaseEditor.ini
 *
 * @param Parameters - Unused for this test
 * @return	TRUE if the test was successful, FALSE otherwise
 */
bool FLineTraceSingleByChannel::RunTest(const FString& Parameters)
{	
	// Create map
	UWorld* World = FAutomationEditorCommonUtils::CreateNewMap();
	TestNotNull(TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World);
	CollisionAutomationTests::TestBase = this;

	static FName TraceIdent = FName(TEXT("TestTrace"));

	FVector StartPos;
	FVector EndPos;
	ECollisionChannel Channel = ECC_WorldStatic;

	UCollisionAutomationTestConfigData* Data = UCollisionAutomationTestConfigData::StaticClass()->GetDefaultObject<UCollisionAutomationTestConfigData>();

	for (int32 iTest = 0; iTest < Data->LineTraceSingleByChannelTests.Num(); iTest++)
	{
		FCollisionTestEntry OneElement = Data->LineTraceSingleByChannelTests[iTest];

		AStaticMeshActor* TestRayMeshActor = CollisionAutomationTests::CreateShapeMeshActor(*OneElement.RootShapeAsset, OneElement.HitResult.TraceEnd);
		
		if (TestRayMeshActor != nullptr)
		{
			// Create the Actor to check against			
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("BlockAll"));
			TestRayMeshActor->SetActorEnableCollision(true);
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.bSimulatePhysics = true;

			// Setup trace start/end
			StartPos = OneElement.HitResult.TraceStart;			
			EndPos = TestRayMeshActor->GetActorLocation();
						
			// Do the trace
			FHitResult OutHit;
			bool WasBlocked = World->LineTraceSingleByChannel(OutHit,StartPos,EndPos,Channel);
			bool BlockedBySpecified = false;
			if (WasBlocked == true)
			{
				if (OutHit.GetActor() == TestRayMeshActor)
				{
					BlockedBySpecified = true;
					// This generates a snippet you can copy/paste into the ini file for test validation
					//UE_LOG(CollisionAutomationTestLog, Log, TEXT("%d:HitResult=(%s)"), iTest + 1, *(CollisionAutomationTests::HitToString(OutHit)));

					CollisionAutomationTests::CheckVector(OutHit.ImpactNormal, OneElement.HitResult.ImpactNormal, TEXT("LineTraceSingleByChannel"), TEXT("ImpactNormal"), iTest);
					CollisionAutomationTests::CheckVector(OutHit.Normal, OneElement.HitResult.Normal, TEXT("LineTraceSingleByChannel"), TEXT("Normal"), iTest);
					CollisionAutomationTests::CheckVector(OutHit.ImpactPoint, OneElement.HitResult.ImpactPoint, TEXT("LineTraceSingleByChannel"), TEXT("ImpactPoint"), iTest);
					CollisionAutomationTests::CheckFloat(OutHit.Time, OneElement.HitResult.Time, TEXT("LineTraceSingleByChannel"), TEXT("Time"), iTest);									
				}
			}
			TestTrue(FString::Printf(TEXT("Test %d:LineTraceSingleByChannel to %s failed. Should return blocking hit"), iTest + 1, *TestRayMeshActor->GetName()), BlockedBySpecified);

			// Change the collision profile and ensure we dont get a blocking hit
			UShapeComponent* CollisionComponent = Cast<UShapeComponent>(TestRayMeshActor->GetRootComponent());			
			if (CollisionComponent != nullptr)
			{
				CollisionComponent->SetCollisionProfileName(TEXT("OverlapAll"));
				CollisionComponent->SetSimulatePhysics(true);
			}
				
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("OverlapAll"));
			WasBlocked = World->LineTraceSingleByChannel(OutHit, StartPos, EndPos, Channel);
			TestFalse(FString::Printf(TEXT("Test %d:LineTraceSingleByChannel to %s failed. Should not return blocking hit"), iTest + 1, *TestRayMeshActor->GetName()), WasBlocked);			
		}
		// Remove the actor
		TestRayMeshActor->Destroy();
	}

	return true;
}
bool FArchiveTest::RunTest( const FString& Parameters )
{
    // Key metadata
    TSharedPtr< FLocMetadataObject > KeyMetadataA = MakeShareable( new FLocMetadataObject );
    TSharedPtr< FLocMetadataObject > KeyMetadataB = 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 );

    // Setup source item
    FLocItem SourceA( TEXT("TextA") );
    SourceA.MetadataObj = MakeShareable( new FLocMetadataObject(*SourceMetadataA) );

    FLocItem Translation = SourceA;
    Translation.Text = TEXT("TranslatedTextA");

    FString TestNamespace = TEXT("TestNamespace");
    FString SourceAKey = TEXT("TextA");

    // Test entry add
    {
        bool TestOptionalTrue = true;
        bool TestOptionalFalse = false;

        // bIsOptional is not used as a key.  We ensure adding entries where the bIsOptional member is the only difference works as expected.
        FInternationalizationArchive TestArchive;
        TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, NULL, TestOptionalTrue );
        // Add duplicate entry that differs in bIsOptional flag.  This add should report success because we already have an entry with matching
        //  namespace/source/keymetadata.  Differences in bIsOptional are not taken into consideration.
        bool bResult = TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, NULL, TestOptionalFalse );
        TestTrue( TEXT("AddEntry result = true"), bResult);

        // We should only have one entry in the archive
        int32 EntryCount = 0;
        for(auto Iter = TestArchive.GetEntriesBySourceTextIterator(); Iter; ++Iter, ++EntryCount);
        TestEqual( TEXT("EntryCount == 1"), EntryCount, 1 );

        // Make sure the original bIsOptional value is not overwritten by our second add.
        TSharedPtr< FArchiveEntry > FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, NULL );
        if( !FoundEntry.IsValid() )
        {
            AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
        }
        else
        {
            TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->bIsOptional == TestOptionalTrue );
        }
    }

    // Test lookup an entry
    {
        {
            FInternationalizationArchive TestArchive;
            TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, KeyMetadataA, false );

            TSharedPtr< FArchiveEntry > FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, KeyMetadataA );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->Namespace == TestNamespace );
                TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == SourceA );
                TestTrue( TEXT("FoundEntry->Translation == Translation"), FoundEntry->Translation == Translation );
                if( FoundEntry->KeyMetadataObj == KeyMetadataA )
                {
                    AddError(TEXT("FArchiveEntry KeyMetadataObj is not a unique object."));
                }
                TestTrue( TEXT("FoundEntry->KeyMetadataObj == KeyMetadataA"), *(FoundEntry->KeyMetadataObj) == *(KeyMetadataA) );
            }

            // Passing in a mismatched key metadata will fail to find the entry.  Any fallback logic is intended to happen at runtime
            FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, NULL );
            TestInvalid( TEXT("!FoundEntry.IsValid()"), FoundEntry);

            FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, MakeShareable( new FLocMetadataObject() ) );
            TestInvalid( TEXT("!FoundEntry.IsValid()"), FoundEntry);

            FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, KeyMetadataB );
            TestInvalid( TEXT("!FoundEntry.IsValid()"), FoundEntry);
        }

        // Ensure we can properly lookup entries with non-null but empty key metadata
        {
            FInternationalizationArchive TestArchive;
            TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, MakeShareable( new FLocMetadataObject() ), false );

            TSharedPtr< FArchiveEntry > FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, NULL );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->Namespace == TestNamespace );
                TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == SourceA );
            }
        }

        // Ensure we can properly lookup entries with null key metadata
        {
            FInternationalizationArchive TestArchive;
            TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, NULL, false );

            TSharedPtr< FArchiveEntry > FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, NULL );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->Namespace == TestNamespace );
                TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == SourceA );
            }

            // Test lookup with non-null but empty key metadata
            FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, MakeShareable( new FLocMetadataObject() ) );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->Namespace == TestNamespace );
                TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == SourceA );
            }
        }

        // Ensure lookup where source metadata has * prefixed entries work as expected.  Note: The source metadata object
        //   supports a * prefix on metadata names which modifies the way we perform metadata comparison(ignores entry type and value, only name is checked)
        {
            FLocItem SourceCompare( TEXT("TextA") );
            SourceCompare.MetadataObj = MakeShareable( new FLocMetadataObject() );
            SourceCompare.MetadataObj->SetStringField( TEXT("*IsMature"), TEXT("") );

            FInternationalizationArchive TestArchive;
            // Added entry with String *IsMature entry
            TestArchive.AddEntry( TestNamespace, SourceAKey, SourceCompare, Translation, KeyMetadataA, false );

            // Finding entry using a source that has Boolean *IsMature
            TSharedPtr< FArchiveEntry > FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, KeyMetadataA );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                TestTrue( TEXT("FoundEntry->Namespace == Namespace"), FoundEntry->Namespace == TestNamespace );
                TestTrue( TEXT("FoundEntry->Source == Source"), FoundEntry->Source == SourceA );
            }

            // Attempting to add an entry that only differs by a * prefexed source metadata entry value or type will result in success since
            //  a 'matching' entry already exists in the archive.  We should, however, only have one entry in the archive
            bool bResult = TestArchive.AddEntry( TestNamespace, SourceAKey, SourceA, Translation, KeyMetadataA, false );

            TestTrue( TEXT("AddEntry result = true"), bResult);

            // We should only have one entry in the archive
            int32 EntryCount = 0;
            for(auto Iter = TestArchive.GetEntriesBySourceTextIterator(); Iter; ++Iter, ++EntryCount);
            TestEqual( TEXT("EntryCount == 1"), EntryCount, 1 );

            // Check to see that the original type/value of the * prefixed entry did not get modified
            FoundEntry = TestArchive.FindEntryByKey( TestNamespace, SourceAKey, KeyMetadataA );
            if( !FoundEntry.IsValid() )
            {
                AddError(TEXT("FArchiveEntry could not find entry using FindEntryByKey."));
            }
            else
            {
                if( FoundEntry->Source.MetadataObj->HasTypedField< ELocMetadataType::String >( TEXT("*IsMature") ) )
                {
                    TestTrue( TEXT("Metadata Type == String and Value == Empty string"), FoundEntry->Source.MetadataObj->GetStringField( TEXT("*IsMature") ) == TEXT("") );
                }
                else
                {
                    AddError(TEXT("FArchiveEntry * prefixed metadata entry on source object was modified unexpectedly."));
                }
            }
        }
    }

    return true;
}