Example #1
0
        public static async Task ExecuteTestAsync(TestCaseInformation caseInfo)
        {
            Assert.IsTrue(caseInfo.Method.IsPublic && caseInfo.Method.IsStatic);

            // TODO:
            var path = Path.GetFullPath(Path.Combine(
                                            caseInfo.Method.DeclaringType.Assembly.Location,
                                            "..", "..", "..", "..", "..",
                                            "IL2C.Core.Test.Target",
                                            caseInfo.CategoryName,
                                            caseInfo.Id,
                                            caseInfo.Id + ".cs"));

            if (File.Exists(path))
            {
                TestContext.AddTestAttachment(path, "Test case");
            }

            // Split current thread context.
            await Task.Yield();

            ///////////////////////////////////////////////

            // Step 1-1: Create translation context.
            var translateContext = new TranslateContext(
                caseInfo.Method.DeclaringType.Assembly.Location,
                true);

            // Step 1-2: Prepare target methods.
            var targetTypes = new HashSet <string>(
                new[] { caseInfo.Method }.
                Concat(caseInfo.AdditionalMethods).
                Select(method => method.DeclaringType).
                Concat(caseInfo.AdditionalTypes).
                Select(type => type.FullName).
                Distinct());
            var targetMethods = new[] { caseInfo.Method }.
                Concat(caseInfo.AdditionalMethods).
            GroupBy(method => method.Name).
            ToDictionary(g => g.Key, g => g.ToArray());

            var prepared = AssemblyPreparer.Prepare(
                translateContext,
                t => targetTypes.Contains(t.FriendlyName),
                m => targetMethods.ContainsKey(m.Name));

            // Step 1-3: Extract prepared target type/caseInfo.Method informations.
            var targetType =
                translateContext.Assembly.Modules
                .First().Types
                .First(t => t.FriendlyName == caseInfo.Method.DeclaringType.FullName);
            var targetMethod =
                targetType.DeclaredMethods
                .First(m => m.Name == caseInfo.Method.Name);
            var targetAdditionalMethods =
                targetType.DeclaredMethods
                .Where(m => (caseInfo.AdditionalMethods.FirstOrDefault(am => m.Name == am.Name) != null))
                .ToArray();

            // Step 1-4: Translate caseInfo.Method bodies.
            var translatedPath =
                Path.Combine(
                    Path.GetDirectoryName(caseInfo.Method.DeclaringType.Assembly.Location),
                    caseInfo.CategoryName,
                    caseInfo.Id,
                    caseInfo.UniqueName);

            var logw    = new StringWriter();
            var storage = new CodeTextStorage(logw, translatedPath, false, "    ");

            AssemblyWriter.WriteHeader(
                storage,
                translateContext,
                prepared);
            var sourceFiles = AssemblyWriter.WriteSourceCode(
                storage,
                translateContext,
                prepared,
                true,
                DebugInformationOptions.CommentOnly);

            // Step 1-5: Write source code into a file from template.
            var expectedType = targetMethod.ReturnType;

            var sourceCodeStream = new MemoryStream();
            await TestUtilities.CopyResourceToStreamAsync(
                sourceCodeStream,
                // If the target caseInfo.Method result is void-type, we have to use void-type tolerant template.
                (expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak))? "test_void.c" : "test.c");

            sourceCodeStream.Position = 0;
            var sourceCode = new StreamReader(sourceCodeStream);

            var constants = caseInfo.Arguments.
                            Zip(targetMethod.Parameters, (arg, p) => new Constant(
                                    p.ParameterName,
                                    p.TargetType,
                                    arg?.GetType(),
                                    Utilities.GetCLanguageExpression(arg))
                                ).
                            ToArray();
            var argumentList = constants.
                               Select(constant => new Constant(
                                          "_" + constant.SymbolName,
                                          constant.TargetType,
                                          null,
                                          GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))).
                               ToArray();

            var arguments = argumentList;
            var locals    = argumentList.
                            Select(argument =>
                                   new Constant(
                                       argument.SymbolName,
                                       argument.TargetType,
                                       argument.ExpressionType,
                                       Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue))).
                            ToArray();

            if (!(expectedType.IsVoidType || (caseInfo.Assert == TestCaseAsserts.CauseBreak)))
            {
                // VERY DIRTY:
                constants = constants.Concat(new Constant[]
                {
                    new Constant(
                        "expected",
                        expectedType,
                        caseInfo.Expected?.GetType(),
                        Utilities.GetCLanguageExpression(caseInfo.Expected)),
                }).
                            ToArray();
                arguments = constants.
                            Select(constant => new Constant(
                                       "_" + constant.SymbolName,
                                       constant.TargetType,
                                       null,
                                       GetCLangaugeSafeConversionExpression(constant.TargetType, constant.ExpressionType, constant.SymbolName))).
                            ToArray();
                locals = arguments.
                         Select(argument =>
                                new Constant(
                                    argument.SymbolName,
                                    argument.TargetType,
                                    argument.ExpressionType,
                                    Utilities.GetCLanguageExpression(argument.TargetType.InternalStaticEmptyValue))).
                         Concat(new Constant[]
                {
                    new Constant(
                        "_actual",
                        expectedType,
                        caseInfo.Expected?.GetType(),
                        Utilities.GetCLanguageExpression(expectedType.InternalStaticEmptyValue)),
                }).
                         ToArray();
            }

            // Construct test definitions.
            var expectedSymbolName = locals.
                                     Any(entry => (entry.SymbolName == "_expected") && entry.TargetType.IsReferenceType) ?
                                     "frame__._expected" :
                                     "_expected";
            var actualSymbolName = locals.
                                   Any(entry => (entry.SymbolName == "_actual") && entry.TargetType.IsReferenceType) ?
                                   "frame__._actual" :
                                   "_actual";
            var replaceValues = new Dictionary <string, object>
            {
                { "testName", targetMethod.FriendlyName },
                { "type", targetMethod.ReturnType.CLanguageTypeName },
                { "constants", string.Join(" ", constants.
                                           Select(entry => string.Format("{0} {1} = {2};",
                                                                         (entry.ExpressionType != null) ? Utilities.GetCLanguageTypeName(entry.ExpressionType) : entry.TargetType.CLanguageTypeName,
                                                                         entry.SymbolName,
                                                                         entry.Expression))) },
                { "locals", string.Join(" ", locals.
                                        Where(entry => !entry.TargetType.IsReferenceType).
                                        Select(entry => string.Format("{0} {1} = {2};",
                                                                      entry.TargetType.CLanguageTypeName,
                                                                      entry.SymbolName,
                                                                      entry.Expression))) },
                { "frames", string.Join(" ", locals.
                                        Where(entry => entry.TargetType.IsReferenceType).
                                        Select(entry => string.Format("{0} {1};",
                                                                      entry.TargetType.CLanguageTypeName,
                                                                      entry.SymbolName))) },
                { "frameCount", locals.
                  Where(entry => entry.TargetType.IsClass).Count() },
                { "arguments", string.Join(" ", arguments.
                                           Select(entry => string.Format("{0}{1} = {2};",
                                                                         entry.TargetType.IsReferenceType ? "frame__." : string.Empty,
                                                                         entry.SymbolName,
                                                                         entry.Expression))) },
                { "actual", actualSymbolName },
                { "function", targetMethod.CLanguageFunctionName },
                { "argumentList", string.Join(", ", argumentList.
                                              Select(arg => string.Format(
                                                         "{0}{1}",
                                                         arg.TargetType.IsReferenceType ? "frame__." : string.Empty,
                                                         arg.SymbolName))) },
                { "equality", GetCLanguageCompareExpression(expectedType, expectedSymbolName, actualSymbolName) },
                { "format", GetCLanguagePrintFormatFromType(targetMethod.ReturnType) },
                { "expectedExpression", GetCLanguagePrintArgumentExpression(expectedType, expectedSymbolName) },
                { "actualExpression", GetCLanguagePrintArgumentExpression(expectedType, actualSymbolName) },
                { "sourcePath", translateContext.Assembly.Name + "_bundle.c" }
            };

            // Step 1-6: Write Visual C++ project file and Visual Studio Code launch config from template.
            //     Note: It's only debugging purpose. The test doesn't use.
            var vcxprojTemplatePath = Path.Combine(translatedPath, "test.vcxproj");
            await TestUtilities.CopyResourceToTextFileAsync(vcxprojTemplatePath, "test.vcxproj", replaceValues);

            TestContext.AddTestAttachment(vcxprojTemplatePath, "Generated VC++ project");

            var launchTemplatePath = Path.Combine(translatedPath, ".vscode", "launch.json");
            await TestUtilities.CopyResourceToTextFileAsync(launchTemplatePath, "launch.json", replaceValues);

            var sourcePath = Path.Combine(translatedPath, "test.c");
            await TestUtilities.WriteTextFileAsync(sourcePath, sourceCode, replaceValues);

            ///////////////////////////////////////////////
            // Step 2: Test and verify result by real IL code at this runtime.

            object rawResult;

            switch (caseInfo.Assert)
            {
            case TestCaseAsserts.IgnoreValidateInvokeResult:
                break;

            case TestCaseAsserts.CauseBreak:
                rawResult = null;
                break;

            default:
                CultureInfo.CurrentCulture   = CultureInfo.InvariantCulture;
                CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
                rawResult = caseInfo.Method.Invoke(null, caseInfo.Arguments);
                Assert.AreEqual(caseInfo.Expected, rawResult);
                break;
            }

            ///////////////////////////////////////////////
            // Step 3: Test compiled C source code and execute.

            string sanitized = null;

            try
            {
#if DEBUG
                var executedResult = await GccDriver.CompileAndRunAsync(
                    gccBasePath,
                    false,
                    sourcePath,
                    Path.Combine(il2cRuntimePath, "include"));
#else
                var executedResult = await GccDriver.CompileAndRunAsync(
                    gccBasePath,
                    true,
                    sourcePath,
                    Path.Combine(il2cRuntimePath, "include"));
#endif

                sanitized = executedResult.Trim(' ', '\r', '\n');
            }
            catch (Exception ex)
            {
                if ((caseInfo.Assert == TestCaseAsserts.CauseBreak) && ex.Message.Contains("ExitCode=-2147483645"))
                {
                    return;
                }
                throw;
            }

            Assert.IsFalse(caseInfo.Assert == TestCaseAsserts.CauseBreak, "Code didn't break.");

            ///////////////////////////////////////////////
            // Step 4: Verify result.

            Assert.AreEqual("Success", sanitized);
        }
Example #2
0
        public static void Translate(
            TextWriter tw,
            string assemblyPath,
            string outputPath,
            bool readSymbols,
            bool enableCpp,
            DebugInformationOptions debugInformationOptions)
        {
            tw.Write("IL2C: Preparing assembly: \"{0}\" ...", Path.GetFullPath(assemblyPath));

            if (Directory.Exists(outputPath) == false)
            {
                try
                {
                    Directory.CreateDirectory(outputPath);
                }
                catch
                {
                }
            }

            var translateContext  = new TranslateContext(assemblyPath, readSymbols);
            var preparedFunctions = AssemblyPreparer.Prepare(translateContext);

            tw.WriteLine(" done.");

            var assemblyName   = Path.GetFileNameWithoutExtension(assemblyPath);
            var filePath       = Path.Combine(outputPath, assemblyName);
            var sourceFilePath = filePath + (enableCpp ? ".cpp" : ".c");

            tw.Write("IL2C: Writing source code: \"{0}\" ...", Path.GetFullPath(sourceFilePath));

            using (var fsSource = new FileStream(
                       sourceFilePath,
                       FileMode.Create,
                       FileAccess.ReadWrite,
                       FileShare.None))
            {
                var twSource = CodeTextWriter.Create(fsSource, "    ");
                AssemblyWriter.WriteSourceCode(
                    twSource, translateContext, preparedFunctions, debugInformationOptions);
                twSource.Flush();
            }

            tw.WriteLine(" done.");

            var headerFilePath = filePath + ".h";

            tw.Write("IL2C: Writing header: \"{0}\" ...", Path.GetFullPath(headerFilePath));

            using (var fsHeader = new FileStream(
                       headerFilePath,
                       FileMode.Create,
                       FileAccess.ReadWrite,
                       FileShare.None))
            {
                var twHeader = CodeTextWriter.Create(fsHeader, "    ");
                AssemblyWriter.WriteHeader(twHeader, translateContext, preparedFunctions);
                twHeader.Flush();
            }

            tw.WriteLine(" done.");
        }