public void While_loop_should_be_converted_to_if_statements()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act
                        var rewrittenNode = rewriter.Visit(m);

                        //Assert
                        var whileStatements = rootNode.DescendantNodes().OfType <WhileStatementSyntax>().ToArray();
                        foreach (var whileStatement in whileStatements)
                        {
                            var whileCondition        = (BinaryExpressionSyntax)whileStatement.Condition;
                            var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>().Where(s => s.Condition.ToString() == whileCondition.ToString()).ToArray();
                            Assert.NotEmpty(rewrittenIfStatements);
                        }

                        var rewrittenWhileStatements = rewrittenNode.DescendantNodes().OfType <WhileStatementSyntax>().ToArray();
                        Assert.Empty(rewrittenWhileStatements);
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        public void Single_child_in_block_with_parent_of_kind_block_should_be_moved_one_level_up()
        {
            // Arrange
            var rootNode   = CSharpSyntaxTree.ParseText(@"
            using System;

            namespace Frisia.CodeReduction
            {
                class Program
                {
                    public static void Method(int a)
                    {
                        {
                            {
                                {
                                    Console.WriteLine (""First content in block."");
                                }
                                {
                                    Console.WriteLine (""Second content in block."");
                                }
                            }
                        }
                    }
                }
            }
            ").GetRoot();
            var m          = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>().First();
            var conditions = new List <ExpressionSyntax>();
            var solver     = new Z3Solver();
            var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
            var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

            // Act
            var rewrittenNode = rewriter.Visit(rootNode);

            var blockStatementsWithParentBlockAndSingleChild = rootNode.DescendantNodes().OfType <BlockSyntax>()
                                                               .Where(b => b.Parent.Kind() == SK.Block && b.ChildNodes().Count() == 1);
            var rewrittenBlockStatementsWithParentBlockAndSingleChild = rewrittenNode.DescendantNodes().OfType <BlockSyntax>()
                                                                        .Where(b => b.Parent.Kind() == SK.Block && b.ChildNodes().Count() == 1);

            // Assert
            Assert.NotEmpty(blockStatementsWithParentBlockAndSingleChild);
            Assert.Empty(rewrittenBlockStatementsWithParentBlockAndSingleChild);
        }
        public void Rewritten_TestCases_should_exists()
        {
            foreach (var tc in TestCases)
            {
                // Debugging
                if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                {
                    continue;
                }

                var timer = new Stopwatch();

                // Arrange
                var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                foreach (var m in methods)
                {
                    var conditions = new List <ExpressionSyntax>();
                    var solver     = new Z3Solver();
                    var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                    var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                    // Act
                    timer.Start();
                    var rewrittenNode = (MethodDeclarationSyntax)rewriter.Visit(m);
                    timer.Stop();

                    rootNode = rootNode.ReplaceNode(m, rewrittenNode);
                }

                var directory         = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\")) + "TestCasesRewritten\\";
                var path              = $"{directory}{tc.Key}";
                var rewrittenNodeText = $"// This code was generated by Frisia.Rewriter.{Environment.NewLine}// Loop iterations: {LoopIterations}{Environment.NewLine}// Date: {DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss")}{Environment.NewLine}// Time: {timer.Elapsed}{Environment.NewLine}{Environment.NewLine}{rootNode.ToFullString()}";

                File.WriteAllText(path, rewrittenNodeText);

                // Assert
                Assert.True(File.Exists(path));
            }
        }
        public void Each_block_statement_should_contain_single_statement()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act

                        var rewrittenNode = rewriter.Visit(m);

                        var blocks = rewrittenNode.DescendantNodes().OfType <BlockSyntax>();

                        // Assert
                        Assert.All(blocks, b => b.ChildNodes().OfType <StatementSyntax>().Where(x => x.Kind() != SK.ExpressionStatement &&
                                                                                                x.Kind() != SK.LocalDeclarationStatement).SingleOrDefault());
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        public void If_statement_should_not_contain_logical_OR_expression()
        {
            foreach (var tc in TestCases)
            {
                try
                {
                    // Debugging
                    if (!string.IsNullOrEmpty(TestToDebug) && tc.Key != TestToDebug)
                    {
                        continue;
                    }

                    // Arrange
                    var rootNode = CSharpSyntaxTree.ParseText(tc.Value).GetRoot();
                    var methods  = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

                    foreach (var m in methods)
                    {
                        var conditions = new List <ExpressionSyntax>();
                        var solver     = new Z3Solver();
                        var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                        var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);

                        // Act
                        var rewrittenNode = rewriter.Visit(m);

                        //Assert
                        var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>();

                        Assert.All(rewrittenIfStatements, s => Assert.True(s.Condition.Kind() != SK.LogicalOrExpression));
                    }
                }
                catch (Exception ex)
                {
                    throw new TestCaseFailedException(tc.Key, ex);
                }
            }
        }
        public (IEnumerable <Set> sets, SyntaxNode rewrittenNode, TimeSpan elapsed) ProvideParameters(MethodDeclarationSyntax method, ScriptState state)
        {
            var sets       = new List <Set>();
            var conditions = new List <ExpressionSyntax>();
            var sms        = new SymbolicMemoryState(method.ParameterList.Parameters);
            var rewriter   = new FrisiaSyntaxRewriter(
                conditions,
                method.ParameterList.Parameters,
                sms,
                solver,
                logger,
                loopIterations,
                visitUnsatisfiablePaths,
                visitTimeoutPaths,
                logFoundBranches,
                timeout);

            var rewriterTimer = Stopwatch.StartNew();
            var rewrittenNode = (MethodDeclarationSyntax)rewriter.Visit(method);

            rewriterTimer.Stop();
            logger.Info($"{method.Identifier.Text} rewritten in {rewriterTimer.Elapsed}");

            IList <string[]> results = rewriter.GetResults();

            // Add default values
            var defaults = new string[method.ParameterList.Parameters.Count];

            for (int i = 0; i < method.ParameterList.Parameters.Count; i++)
            {
                defaults[i] = TypeHelper.GetDefaultValue(method.ParameterList.Parameters[i].Type).ToString();
            }
            results.Add(defaults);

            logger.Info("Determining results...");
            foreach (var r in results)
            {
                var returnValue = Runner.Run(state, method, r, timeout);

                var parameters = new Parameter[r.Length];

                for (int i = 0; i < r.Length; i++)
                {
                    parameters[i] = new Parameter
                    {
                        Value    = r[i],
                        TypeName = TypeHelper.GetFullTypeName(method.ParameterList.Parameters[i].Type)
                    };
                }

                var s = new Set
                {
                    MethodName     = method.Identifier.Text,
                    Parameters     = parameters,
                    ResultTypeName = TypeHelper.GetFullTypeName(method.ReturnType),
                    ExpectedResult = returnValue
                };

                sets.Add(s);
            }

            return(sets, rewrittenNode, rewriterTimer.Elapsed);
        }
        public void AND_expressions_should_be_replaced_correctly()
        {
            // Arrange
            var rootNode = CSharpSyntaxTree.ParseText(@"
            using System;

            namespace Frisia.CodeReduction
            {
                class Program
                {
                    public static void Method(int a, int b)
                    {
                        if (a > 0 && b > 0)
                        {
                            Console.WriteLine(""a > 0 && b > 0"");
                                
                            if (a > 1 && b > 1)
                            {
                                Console.WriteLine(""a > 1 && b > 1"");

                                if (a > 2 && b > 2)
                                {
                                    Console.WriteLine(""a > 2 && b > 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a > 2 && b > 2)"");
                                }
                            }
                            else
                            {
                                Console.WriteLine(""!(a > 1 && b > 1)"");

                                if (a > 2 && b > 2)
                                {
                                    Console.WriteLine(""a > 2 && b > 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a > 2 && b > 2)"");
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine(""!(a > 0 && b > 0)"");

                            if (a < 1 && b < 1)
                            {
                                Console.WriteLine(""a < 1 && b < 1"");

                                if (a < 2 && b < 2)
                                {
                                    Console.WriteLine(""a < 2 && b < 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a < 2 && b < 2)"");
                                }
                            }
                            else
                            {
                                Console.WriteLine(""!(a < 1 && b < 1)"");

                                if (a < 2 && b < 2)
                                {
                                    Console.WriteLine(""a < 2 && b < 2"");
                                }
                                else
                                {
                                    Console.WriteLine(""!(a < 2 && b < 2)"");
                                }
                            }
                        }
                    }
                }
            }
            ").GetRoot();

            var methods = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>();

            foreach (var m in methods)
            {
                var conditions = new List <ExpressionSyntax>();
                var solver     = new Z3Solver();
                var sms        = new SymbolicMemoryState(m.ParameterList.Parameters);
                var rewriter   = new FrisiaSyntaxRewriter(conditions, m.ParameterList.Parameters, sms, solver, null, LoopIterations, visitUnsatPaths: true, visitTimeoutPaths: true, logFoundBranches: false, timeout: 5);


                // Act
                var rewrittenNode = rewriter.Visit(rootNode);

                //var ifStatements = rootNode.DescendantNodes().OfType<IfStatementSyntax>().ToArray();
                var rewrittenIfStatements = rewrittenNode.DescendantNodes().OfType <IfStatementSyntax>().ToArray();

                // Assert
                Assert.Equal(26, rewrittenIfStatements.Length);
            }
        }