Пример #1
0
        public static void process_types_allows_for_types_to_refer_to_other_types_in_separate_files()
        {
            var typeAJson = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.file_order.file_order_a.json");
            var typeBJson = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.file_order.file_order_b.json");
            var typeCJson = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.file_order.file_order_c.json");

            var allJsonFiles = new List <SchemaFileRaw>()
            {
                typeAJson, typeBJson, typeCJson
            };
            var schemaProcessor = new UnrealSchemaProcessor(allJsonFiles);

            Assert.That(schemaProcessor.unrealTypeDetails.Count == 3, "The schema processor did not contain the expected number of entries");

            var typeATypeDetails = schemaProcessor.unrealTypeDetails[0];
            var typeBTypeDetails = schemaProcessor.unrealTypeDetails[1];
            var typeCTypeDetails = schemaProcessor.unrealTypeDetails[2];

            Assert.That(typeATypeDetails.UnderlyingQualifiedName == "improbable::codegentests::file_order::TypeA", "The 'TypeA' type is not the first type to be observed");
            Assert.That(typeBTypeDetails.UnderlyingQualifiedName == "improbable::codegentests::file_order::TypeB", "The 'TypeB' type is not the second type to be observed");
            Assert.That(typeCTypeDetails.UnderlyingQualifiedName == "improbable::codegentests::file_order::TypeC", "The 'TypeC' type is not the second type to be observed");

            var typeATypeBFieldReference = typeATypeDetails.FieldDetailsList[0];
            var typeCTypeBFieldReference = typeCTypeDetails.FieldDetailsList[0];

            Assert.That(typeATypeBFieldReference.TypeReference.UnderlyingQualifiedName == typeBTypeDetails.UnderlyingQualifiedName, "The 'TypeA' type does not have a reference to the 'TypeB' type");
            Assert.That(typeCTypeBFieldReference.TypeReference.UnderlyingQualifiedName == typeBTypeDetails.UnderlyingQualifiedName, "The 'TypeC' type does not have a reference to the 'TypeB' type");

            Assert.That(typeCTypeBFieldReference.TypeReference.DefaultInitialisationString == "improbable::codegentests::file_order::TypeB(false, false, false)", "The default initialisation string of TypeB property within TypeC is incorrect");
            Assert.That(typeATypeBFieldReference.TypeReference.DefaultInitialisationString == typeCTypeBFieldReference.TypeReference.DefaultInitialisationString, "The default initialisation string of TypeB property within TypeA is different than the default initialisation string of TypeB property within TypeC");
        }
Пример #2
0
        public static void run_writes_the_expected_output_files_to_disk()
        {
            var fileSystem = GenerateMockFileSystem();

            fileSystem.GetFileInfoMock = (path) =>
            {
                var fileWrapper = new MockFileWrapper(path, Path.GetDirectoryName(path), new DateTime(1, 1, 1));
                fileWrapper.ExistsMock = () => { return(true); };
                fileWrapper.DeleteMock = () => { };
                return(fileWrapper);
            };

            var schemaFileRaw = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.command.json");

            var schemaFileProcessor = new UnrealSchemaProcessor(new List <SchemaFileRaw>()
            {
                schemaFileRaw
            });
            var job = new UnrealCommanderJob(schemaFileProcessor.unrealCommandDetails, new HashSet <string>(), outputDir, fileSystem);

            job.Run();

            Assert.That(fileSystem.WrittenFiles.Count == 2, "UnrealCommanderJob did not write the expected number of files");

            var fullOutputDir = Path.Combine("Codegen", "Test");

            Assert.That(fileSystem.WrittenFiles.Contains(Path.Combine(fullOutputDir, "Commander.h")), "UnrealCommanderJob did not write the expected files");
            Assert.That(fileSystem.WrittenFiles.Contains(Path.Combine(fullOutputDir, "Commander.cpp")), "UnrealCommanderJob did not write the expected files");
        }
Пример #3
0
        public static void process_components_creates_a_list_with_all_expected_components()
        {
            var schemaFileRaw = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.empty_component.json");

            var schemaFilesRaw = new List <SchemaFileRaw> {
                schemaFileRaw
            };
            var schemaProcessor = new UnrealSchemaProcessor(schemaFilesRaw);

            Assert.That(schemaProcessor.unrealComponentDetails.Count == 1, "The schema processor did not contain the expected number of entries");
            Assert.That(schemaProcessor.unrealComponentDetails.First().UnderlyingComponentDefinition == schemaFilesRaw.First().componentDefinitions.First(), "The schema processor did not assign the component definition as expected");
        }
Пример #4
0
        public static void cyclic_dependencies_will_produce_a_helpful_error()
        {
            var commandJson =
                TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.nested_type_order.json");

            var someTypeDefinition = commandJson.typeDefinitions.First(definition => definition.name == "SomeType");

            var newFieldDefinitions = new List <FieldDefinitionRaw>(someTypeDefinition.fieldDefinitions);

            /* This inserts "SomeOtherType this_should_be_cyclic = 3;" into "SomeType".
             *
             * This means:
             *   TestComponentCustomData
             *     - SomeOtherType   TestComponentCustomData.my_member_for_component           // 1
             *     - SomeType        SomeOtherType.my_member_within_some_other_type            // 2
             *     - SomeOtherType   SomeType.this_should_be_cyclic                            // 3
             *     - SomeType        SomeOtherType.my_member_within_some_other_type"           // 2 << cyclic dependency detected! Already generating default initialisation string for 2
             */
            {
                newFieldDefinitions.Add(new FieldDefinitionRaw
                {
                    name         = "this_should_be_cyclic",
                    number       = "3",
                    singularType = new TypeReferenceRaw
                    {
                        userType = "improbable.codegentests.nestedtypeorder.SomeOtherType"
                    },
                });

                someTypeDefinition.fieldDefinitions = newFieldDefinitions.ToArray();
            }

            var unrealProcessor = new UnrealSchemaProcessor(new List <SchemaFileRaw> {
                commandJson
            });

            var firstComponentDetails = unrealProcessor.unrealComponentDetails.First();
            var firstFieldDetails     = firstComponentDetails.FieldDetailsList.First();

            string initialisationString = null;

            var exception = Assert.Throws <UnrealUserTypeReference.CyclicTypeReferenceException>(() => { initialisationString = firstFieldDetails.TypeReference.DefaultInitialisationString; });

            Assert.IsNull(initialisationString, "The initialisation string should not have been set in error cases.");

            Assert.AreEqual("Cyclic type reference detected while generating default initialisation string.\n" +
                            "Introduce an 'option', 'list', or 'map' field to break the chain.\n" +
                            "Generation stack:\n" +
                            " - SomeType SomeOtherType.my_member_within_some_other_type\n" +
                            " - SomeOtherType SomeType.this_should_be_cyclic\n" +
                            " - SomeType SomeOtherType.my_member_within_some_other_type",
                            exception.Message);
        }
Пример #5
0
        public static void process_multi_commands_can_have_same_delegate_type()
        {
            var commandJson = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.commands_have_same_delegate.json");

            var clientCmdNames = commandJson.componentDefinitions.ToList().Find(comp => comp.name == "BenchmarkingClient").commandDefinitions.Select(c => c.name).ToList();
            var serverCmdNames = commandJson.componentDefinitions.ToList().Find(comp => comp.name == "BenchmarkingServer").commandDefinitions.Select(c => c.name).ToList();

            clientCmdNames.Sort();
            serverCmdNames.Sort();
            var clientRawCmds = string.Join(", ", clientCmdNames.ToArray());
            var serverRawCmds = string.Join(", ", serverCmdNames.ToArray());

            Assert.That(clientRawCmds == "ping, ping_time2, ping2, ping3", string.Format("expect `ping, ping_time2, ping2, ping3` but got {0}", clientRawCmds));
            Assert.That(serverRawCmds == "ping4, verify_update", string.Format("expect `ping4, verify_update` but got {0}", serverRawCmds));

            UnrealSchemaProcessor unrealProcessor = new UnrealSchemaProcessor(new List <SchemaFileRaw>()
            {
                commandJson
            });
            var components = unrealProcessor.unrealComponentDetails;

            Assert.That(components.Count == 2, "Test schema should contain 2 components");

            var clientComponent = components.Find(c => c.CapitalisedName == "BenchmarkingClient");
            var serverComponent = components.Find(c => c.CapitalisedName == "BenchmarkingServer");

            Assert.That(clientComponent != null, "`BenchmarkingClient` should exist");
            Assert.That(serverComponent != null, "`BenchmarkingServer` should exist");

            var pingClientCommand = clientComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "Ping");
            var pingTime2Command  = clientComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "PingTime2");
            var ping2Command      = clientComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "Ping2");
            var ping3Command      = clientComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "Ping3");
            var verifyCommand     = serverComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "VerifyUpdate");
            var pingServerCommand = serverComponent.CommandDetailsList.Find(cmd => cmd.CapitalisedName == "Ping");

            Assert.That(pingClientCommand != null, "`BenchmarkingClient` should contain `Ping` command");
            Assert.That(pingTime2Command != null, "`BenchmarkingClient` should contain `PingTime2` command");
            Assert.That(ping2Command != null, "`BenchmarkingClient` should contain `Ping2` command");
            Assert.That(ping3Command != null, "`BenchmarkingClient` should contain `Ping3` command");
            Assert.That(verifyCommand != null, "`BenchmarkingServer` should contain `VerifyUpdate` command");
            // `Ping` command in `BenchmarkingServer` can not be generated due to the constraint we added in UnrealSchemaProcessor to accommodate the limitation in our API implementation.
            Assert.That(pingServerCommand == null, "`BenchmarkingServer` should not contain `Ping` command");

            Assert.That(pingClientCommand.UnrealCommandDelegateType == verifyCommand.UnrealCommandDelegateType, "Expect `Ping` in `BenchmarkingClient` has the same delegate as `VerifyUpdate` in `BenchmarkingServer` does");
            Assert.That(pingClientCommand.UnrealCommandDelegateType == pingTime2Command.UnrealCommandDelegateType, "Expect `Ping` in `BenchmarkingClient` has the same delegate as `PingTime2` does");
            Assert.That(ping2Command.UnrealCommandDelegateType == ping3Command.UnrealCommandDelegateType, "Expect `Ping2` has the same delegate as `Ping3` does");

            // Once we remove the constraint for command codegen, the following assertion should be valid.
            //Assert.That(pingClientCommand.UnrealCommandDelegateType == pingServerCommand.UnrealCommandDelegateType, "Expect `Ping` in `BenchmarkingClient` has the same delegate as `Ping` in `BenchmarkingServer` does");
        }
Пример #6
0
        public static void process_types_allows_for_types_to_refer_to_types_declared_later_in_same_file()
        {
            var schemaFileRaw1 = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.type_reference_before_type.json");

            var schemaFilesRaw = new List <SchemaFileRaw>()
            {
                schemaFileRaw1
            };
            var schemaProcessor = new UnrealSchemaProcessor(schemaFilesRaw);

            Assert.That(schemaProcessor.unrealTypeDetails.Count == 2, "The schema processor did not contain the expected number of entries");
            Assert.That(schemaProcessor.unrealTypeDetails[0].UnderlyingQualifiedName == "improbable::codegentests::TypeB", "The 'TypeB' type is not the first type to be observed");
            Assert.That(schemaProcessor.unrealTypeDetails[0].FieldDetailsList[0].TypeReference.UnderlyingQualifiedName == "improbable::codegentests::TypeA", "The 'TypeB' type does not have a reference to the 'TypeA' type");
            Assert.That(schemaProcessor.unrealTypeDetails[1].UnderlyingQualifiedName == "improbable::codegentests::TypeA", "The 'TypeA' type is not the second type to be observed");
        }
Пример #7
0
        public static void clean_removes_the_expected_files()
        {
            var fileSystem      = GenerateMockFileSystem();
            var fileWrapperList = new List <MockFileWrapper>();

            fileSystem.GetFileInfoMock = (path) =>
            {
                var fileWrapper = new MockFileWrapper(path, Path.GetDirectoryName(path), new DateTime(1, 1, 1));
                fileWrapper.ExistsMock = () => { return(true); };
                fileWrapper.DeleteMock = () => { };
                fileWrapperList.Add(fileWrapper);
                return(fileWrapper);
            };

            fileSystem.GetFilesInDirectoryMock = (path, searchpattern, recursive) => { return(new List <IFile>()
                {
                    new MockFileWrapper(path, Path.GetDirectoryName(path), new DateTime(1, 1, 1))
                }); };

            var schemaFileRaw = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.enum.json");

            var schemaFileProcessor = new UnrealSchemaProcessor(new List <SchemaFileRaw>()
            {
                schemaFileRaw
            });
            var job = new UnrealComponentJob(schemaFileProcessor.unrealComponentDetails.First(), outputDir, fileSystem);

            job.Clean();

            Assert.That(fileWrapperList.Count == 5, "clean did not scan for the expected files to be deleted");

            foreach (var fileWrapper in fileWrapperList)
            {
                Assert.That(fileWrapper.DeleteCallCount == 1, "Did not call Delete the expected number of times for a filewrapper");
                Assert.That(fileWrapper.ExistsCallCount == 1, "Did not call Exists the expected number of times for a filewrapper");
            }

            var fullOutputDir = Path.Combine("Codegen", "Test");

            Assert.That(fileWrapperList.Exists((fileWrapper) => fileWrapper.CompletePath == Path.Combine(fullOutputDir, "ExampleEnumComponentComponent.h")));
            Assert.That(fileWrapperList.Exists((fileWrapper) => fileWrapper.CompletePath == Path.Combine(fullOutputDir, "ExampleEnumComponentComponent.cpp")));
            Assert.That(fileWrapperList.Exists((fileWrapper) => fileWrapper.CompletePath == Path.Combine(fullOutputDir, "ExampleEnumComponentComponentUpdate.h")));
            Assert.That(fileWrapperList.Exists((fileWrapper) => fileWrapper.CompletePath == Path.Combine(fullOutputDir, "ExampleEnumComponentComponentUpdate.cpp")));
            Assert.That(fileWrapperList.Exists((fileWrapper) => fileWrapper.CompletePath == Path.Combine(fullOutputDir, "ExampleEnumComponentAddComponentOp.h")));
        }
Пример #8
0
        private ICollection <ICodegenJob> GenerateUnrealJobs(ICollection <SchemaFileRaw> schemaFiles, CodeGeneratorOptions options)
        {
            var jobs = new List <ICodegenJob>();

            var schemaProcessor = new UnrealSchemaProcessor(schemaFiles);

            jobs.AddRange(GenerateUnrealEnumJobs(schemaProcessor.unrealEnumDetails, options.OutputDir));
            jobs.AddRange(GenerateUnrealTypeJobs(schemaProcessor.unrealTypeDetails, options.OutputDir));
            jobs.AddRange(GenerateUnrealComponentJobs(schemaProcessor.unrealComponentDetails, options.OutputDir));
            jobs.AddRange(GenerateUnrealCommandJobs(schemaProcessor.unrealCommandDetails, options.OutputDir));
            jobs.AddRange(GenerateUnrealCommanderJobs(schemaProcessor.unrealCommandDetails, schemaProcessor.allPackageIncludes, options.OutputDir));
            jobs.AddRange(GenerateUnrealEntityTemplateJobs(schemaProcessor.unrealComponentDetails, schemaProcessor.allPackageIncludes, options.OutputDir));
            jobs.AddRange(GenerateUnrealEntityPipelineJobs(schemaProcessor.unrealComponentDetails, options.OutputDir));
            jobs.AddRange(GenerateCommonHeaderJobs(schemaProcessor.unrealComponentDetails, options.OutputDir));
            jobs.AddRange(GenerateUnrealCallbackDispatcherJobs(schemaProcessor.unrealComponentDetails, schemaProcessor.allPackageIncludes, options.OutputDir));

            return(jobs);
        }
Пример #9
0
        public static void data_types_can_include_other_types_independent_of_order()
        {
            var commandJson = TestUtils.GetRawJsonDataFromResource <SchemaFileRaw>("Improbable.CodeGeneration.Resources.json.test.nested_type_order.json");

            var unrealProcessor = new UnrealSchemaProcessor(new List <SchemaFileRaw> {
                commandJson
            });

            var myComponentDetails = unrealProcessor.unrealComponentDetails.First();

            Assert.AreEqual("TestComponent", myComponentDetails.CapitalisedName, "The first component's name does not match an expected value.");
            Assert.AreEqual("TestComponentCustomData", myComponentDetails.CapitalisedDataName, "The first component's data type name does not match an expected value.");

            var firstFieldDetails = myComponentDetails.FieldDetailsList.First();

            Assert.AreEqual("USomeOtherType", firstFieldDetails.TypeReference.UClassName, "The field does not refer to the correct type");

            Assert.AreEqual("improbable::codegentests::nestedtypeorder::SomeOtherType(improbable::codegentests::nestedtypeorder::SomeType(worker::EntityId(0), 0))",
                            firstFieldDetails.TypeReference.DefaultInitialisationString,
                            "Type with nested type has wrong initialisation string");
        }