예제 #1
0
        public void GenerateDependenciesTest()
        {
            var dependent = new SimpleConceptInfo("dd");

            dependent.GetKeyProperties();
            var existingConcepts = new DslModelMock {
                new EntityInfo {
                    Module = new ModuleInfo {
                        Name = "a"
                    }, Name = "b"
                },
                new DataStructureInfo {
                    Module = new ModuleInfo {
                        Name = "c"
                    }, Name = "d"
                },
                new SqlViewInfo {
                    Module = new ModuleInfo {
                        Name = "e"
                    }, Name = "f"
                },
                new SqlFunctionInfo {
                    Module = new ModuleInfo {
                        Name = "g"
                    }, Name = "h"
                },
            };

            var tests = new Dictionary <string, string>
            {
                { "select a.b from c.d, x.y", "SqlDependsOnDataStructureInfo c.d" },
                { "select * from a.b, c.d, e.f, g.h", "SqlDependsOnDataStructureInfo a.b, SqlDependsOnDataStructureInfo c.d, "
                  + "SqlDependsOnSqlViewInfo e.f, SqlDependsOnSqlFunctionInfo g.h" },
                { "with x.y as (select * from a.b) select * from x.y", "SqlDependsOnDataStructureInfo a.b" }
            };

            foreach (var test in tests)
            {
                Console.WriteLine("Test: " + test.Key);
                var dependencies = SqlAnalysis.GenerateDependencies(dependent, existingConcepts, test.Key);

                foreach (dynamic dependency in dependencies)
                {
                    Assert.AreEqual("dd", dependency.Dependent.ToString());
                }

                var actual = TestUtility.Dump(dependencies,
                                              dep => dep.GetType().Name + " " + ConceptInfoHelper.GetKeyProperties(((dynamic)dep).DependsOn));
                Assert.AreEqual(test.Value, actual, "Input: " + test.Key);
            }
        }
예제 #2
0
        public void RemoveCommentsAndText_LargeRandomTest()
        {
            var elements = new[] { "'", "\"", "[", "]", "]]", "--", "/*", "*/", "-", "/", "*", "a", "b", "c", "\r\n" };

            for (int seed = 0; seed < 20; seed++)
            {
                var    sb     = new StringBuilder();
                Random random = new Random(seed);
                for (int c = 0; c < 10000; c++)
                {
                    sb.Append(elements[random.Next(elements.Length)]);
                }
                string sql = sb.ToString();

                string result            = SqlAnalysis.RemoveCommentsAndText(sql);
                string alternativeResult = RemoveCommentsAndText_AlternativeImplementation(sql);
                Console.WriteLine(string.Format("seed, sql, result, alternativeResult: {0}, {1}, {2}, {3}.", seed, sql.Length, result.Length, alternativeResult.Length));
                Assert.AreEqual(alternativeResult, result);
            }
        }
예제 #3
0
        public void RemoveCommentsAndText_LargeRandomTest()
        {
            var elements = new[] { "'", "\"", "[", "]", "]]", "--", "/*", "*/", "-", "/", "*", "a", "b", "c", "\r\n" };

            for (int seed = 0; seed < 20; seed++)
            {
                var sb     = new StringBuilder();
                var random = new Random(seed);
                for (int c = 0; c < 10000; c++)
#pragma warning disable CA5394 // Do not use insecure randomness. The Random class is used here with a 'seed' to make the unit test reproducible.
                {
                    sb.Append(elements[random.Next(elements.Length)]);
                }
#pragma warning restore CA5394 // Do not use insecure randomness
                string sql = sb.ToString();

                string result            = SqlAnalysis.RemoveCommentsAndText(sql);
                string alternativeResult = RemoveCommentsAndText_AlternativeImplementation(sql);
                Console.WriteLine(string.Format("seed, sql, result, alternativeResult: {0}, {1}, {2}, {3}.", seed, sql.Length, result.Length, alternativeResult.Length));
                Assert.AreEqual(alternativeResult, result);
            }
        }
        public async Task DoUpdateAsync()
        {
            if (IsDisposed)
            {
                return;
            }

            var buffer = _currentSnapshot;
            var path   = _document.FilePath;

            // replace with user token
            var token    = _cts.Token;
            var instance = await FsLintVsPackage.Instance.WithCancellation(token);

            // this acts as a throttle
            await Task.Delay(200, token);

            if (Project == null)
            {
                await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

                var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject;

                if (project == null)
                {
                    return;
                }

                if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK)
                {
                    return;
                }

                if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK)
                {
                    return;
                }

                Project = new LintProjectInfo(project.Name, guid, vsHierarchy);
            }

            await Task.Yield();

            var connectionString = SqlAnalyzer.tryFindConnectionString(path);

            if (string.IsNullOrWhiteSpace(connectionString))
            {
                return;
            }

            var loadedSchema = SqlAnalysis.databaseSchema(connectionString);

            if (loadedSchema.IsError)
            {
                return;
            }

            var source     = _currentSnapshot.GetText();
            var sourceText = SourceText.ofString(source);

            var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript(
                filename: path,
                sourceText: sourceText,
                assumeDotNetFramework: false,
                useSdkRefs: true,
                useFsiAuxLib: true,
                previewEnabled: true,
                otherFlags: new string[] { "--targetprofile:netstandard" },
                loadedTimeStamp: FSharpOption <DateTime> .None,
                extraProjectInfo: FSharpOption <object> .None,
                optionsStamp: FSharpOption <long> .None,
                userOpName: FSharpOption <string> .None
                );

            var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token);

            if (errors.Any())
            {
                return;
            }

            var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject(
                filename: path,
                fileversion: 1,
                sourceText: sourceText,
                options: options,
                textSnapshotInfo: FSharpOption <object> .None,
                userOpName: FSharpOption <string> .None
                );

            var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token);

            if (parseResults.ParseHadErrors || checkAnswer.IsAborted)
            {
                return;
            }

            var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value;

            var context = new SqlAnalyzerContext(
                fileName: path,
                content: source.Split('\n'),
                parseTree: parseResults.ParseTree.Value,
                symbols: SqlAnalyzer.getSymbols(checkResults)
                );

            var databaseSchema = loadedSchema.ResultValue;

            var errorMessages =
                from operation in SyntacticAnalysis.findSqlOperations(context)
                from analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema)
                select analysisOutput;

            var oldLintingErrors = this.Factory.CurrentSnapshot;
            var newLintErrors    = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1);

            foreach (var error in errorMessages)
            {
                var span = RangeToSpan(error.Range, buffer);
                newLintErrors.Errors.Add(new LintError(span, error, Project));
            }

            await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (token.IsCancellationRequested)
            {
                return;
            }

            UpdateLintingErrors(newLintErrors);
        }
예제 #5
0
        public void RemoveCommentsAndTextTest()
        {
            var tests = new Dictionary <string, string>()
            {
                { "", null },
                { " ab ", null },
                { "/a-a-a*/a*/", null },

                { "--", "" },
                { "-", null },
                { "a-", null },
                { "a-b", null },
                { "-b", null },
                { "a--b", "a" },
                { "1--2\r3--4\n5--6\r\n", "1\r3\n5\r\n" },
                { "--\r", "\r" },
                { "--\n", "\n" },
                { "---\n", "\n" },

                { "/**/", "" },
                { "/*/", "" },
                { "/*/1", "" },
                { "/*/1*/2", "2" },
                { "/**", "" },
                { "/", "/" },
                { "*", "*" },
                { "1/*2/*3*/4*/5", "15" },
                { "1/*\r/*\n*/\r\n*/2", "12" },
                { "\r\n1\r\n/*2*/\r\n3\r\n", "\r\n1\r\n\r\n3\r\n" },
                { "/***/1", "1" },
                { "/*//**/1*/2", "2" },

                { "''", "" },
                { "1'23'4", "14" },
                { "1'2''''3'''4", "14" },

                { "1/*2", "1" },
                { "1'2", "1" },
                { "1[2", null },
                { "1\"2", null },

                { "1/*2--3*/4--5", "14" },
                { "1--2/*3\r\n4*/", "1\r\n4*/" },
                { "1'2--3\r\n4'5", "15" },
                { "1'2/*3\r\n4'5*/", "15*/" },
                { "1'2[3'4]", "14]" },

                { "[]", null },
                { "1[2'3]4''5", "1[2'3]45" },
                { "1[2--3]4", null },
                { "1[2/*\r\n*/\r\n3]4", null },
                { "1[2]]]]3--4]]]5--6", "1[2]]]]3--4]]]5" },

                { "\"\"", null },
                { "\"1", null },
                { "1\"", null },
                { "1\"23\"4", null },
                { "1\"2/*3\"4*/", null },
                { "1\"2--3\"4", null },
                { "1\"2'3\"4", null },
                { "1\"2]3\"4", null },
                { "1\"2[3\"4/*1", "1\"2[3\"4" },
            };

            foreach (var test in tests)
            {
                string result            = SqlAnalysis.RemoveCommentsAndText(test.Key);
                string alternativeResult = RemoveCommentsAndText_AlternativeImplementation(test.Key);
                Assert.AreEqual(test.Value ?? test.Key, result, "Input: " + test.Key);
                Assert.AreEqual(alternativeResult, result, "Alternative implementation.");
            }
        }
예제 #6
0
        public async Task DoUpdateAsync()
        {
            if (IsDisposed)
            {
                return;
            }

            var buffer = _currentSnapshot;
            var path   = _document.FilePath;

            // replace with user token
            var token    = _cts.Token;
            var instance = await FsLintVsPackage.Instance.WithCancellation(token);

            // this acts as a throttle
            await Task.Delay(200, token);

            if (Project == null)
            {
                await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

                var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject;

                if (project == null)
                {
                    return;
                }

                if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK)
                {
                    return;
                }

                if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK)
                {
                    return;
                }

                Project = new LintProjectInfo(project.Name, guid, vsHierarchy);
            }

            await Task.Yield();

            var connectionString = SqlAnalyzer.tryFindConnectionString(path);

            if (string.IsNullOrWhiteSpace(connectionString))
            {
                return;
            }



            var source     = _currentSnapshot.GetText();
            var sourceText = SourceText.ofString(source);

            var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript(
                filename: path,
                source: sourceText,
                assumeDotNetFramework: false,
                useSdkRefs: true,
                useFsiAuxLib: true,
                previewEnabled: true,
                otherFlags: new string[] { "--targetprofile:netstandard" },
                loadedTimeStamp: FSharpOption <DateTime> .None,
                extraProjectInfo: FSharpOption <object> .None,
                optionsStamp: FSharpOption <long> .None,
                userOpName: FSharpOption <string> .None,
                sdkDirOverride: FSharpOption <string> .None
                );

            var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token);

            if (errors.Any())
            {
                return;
            }

            var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject(
                filename: path,
                fileVersion: 1,
                sourceText: sourceText,
                options: options,
                userOpName: FSharpOption <string> .None
                );

            var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token);

            if (parseResults.ParseHadErrors || checkAnswer.IsAborted)
            {
                return;
            }

            var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value;

            var context = new SqlAnalyzerContext(
                fileName: path,
                content: source.Split('\n'),
                parseTree: parseResults.ParseTree.Value,
                symbols: SqlAnalyzer.getSymbols(checkResults)
                );

            var operationBlocks = SyntacticAnalysis.findSqlOperations(context);
            var loadedSchema    = SqlAnalysis.databaseSchema(connectionString);

            var errorMessages = new List <Message>();

            if (loadedSchema.IsError)
            {
                foreach (var operation in operationBlocks)
                {
                    var containsSkipAnalysis = operation.blocks.Any(block => block.IsSkipAnalysis);
                    foreach (var block in operation.blocks)
                    {
                        var blockRange = block.Range();
                        if ((block.IsQuery || block.IsTransaction) && OptionModule.IsSome(blockRange) && !containsSkipAnalysis)
                        {
                            var internalError = (loadedSchema.ErrorValue ?? "").Replace("3D000:", "").Replace("28P01:", "");
                            var fullError     = $"Error occured while trying to connect to the database using the configured connection string in NPGSQL_FSHARP in order to perform static analysis:{internalError}";
                            var errorMessage  = new Message(
                                type: "Error",
                                message: fullError,
                                code: "SQL101",
                                severity: Severity.Warning,
                                range: blockRange.Value,
                                fixes: Microsoft.FSharp.Collections.FSharpList <Fix> .Empty
                                );

                            errorMessages.Add(errorMessage);
                        }
                    }
                }
            }
            else
            {
                var databaseSchema = loadedSchema.ResultValue;
                foreach (var operation in operationBlocks)
                {
                    foreach (var analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema))
                    {
                        errorMessages.Add(analysisOutput);
                    }
                }
            }

            var oldLintingErrors = this.Factory.CurrentSnapshot;
            var newLintErrors    = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1);

            foreach (var error in errorMessages)
            {
                var span = RangeToSpan(error.Range, buffer);
                newLintErrors.Errors.Add(new LintError(span, error, Project));
            }

            await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (token.IsCancellationRequested)
            {
                return;
            }

            UpdateLintingErrors(newLintErrors);
        }
예제 #7
0
        public void GenerateDependenciesTestToObject()
        {
            var dependent = new SimpleConceptInfo("dd");

            dependent.GetKeyProperties();
            var existingConcepts = new DslModelMock {
                new EntityInfo {
                    Module = new ModuleInfo {
                        Name = "a"
                    }, Name = "b"
                },
                new DataStructureInfo {
                    Module = new ModuleInfo {
                        Name = "c"
                    }, Name = "d"
                },
                new SqlViewInfo {
                    Module = new ModuleInfo {
                        Name = "e"
                    }, Name = "f"
                },
                new SqlFunctionInfo {
                    Module = new ModuleInfo {
                        Name = "g"
                    }, Name = "h"
                },
                new EntityInfo {
                    Module = new ModuleInfo {
                        Name = "x"
                    }, Name = "y"
                },
                new SqlViewInfo {
                    Module = new ModuleInfo {
                        Name = "x"
                    }, Name = "y"
                },
                new SqlFunctionInfo {
                    Module = new ModuleInfo {
                        Name = "x"
                    }, Name = "y"
                },
            };

            var tests = new Dictionary <string, string>
            {
                { "a.a", "" },
                { "b.b", "" },
                { "a.b.a", "" },
                { "a.a.b", "" },
                { "a", "" },
                { "b", "" },

                { "a.b", "SqlDependsOnDataStructureInfo a.b" },
                { "c.d", "SqlDependsOnDataStructureInfo c.d" },
                { "e.f", "SqlDependsOnSqlViewInfo e.f" },
                { "g.h", "" },
                { "g.h(SYSDATETIME())", "SqlDependsOnSqlFunctionInfo g.h" },

                { "x.y(SYSDATETIME())", "SqlDependsOnSqlFunctionInfo x.y" },
                { "x.y", "SqlDependsOnDataStructureInfo x.y, SqlDependsOnSqlViewInfo x.y" },
            };

            foreach (var test in tests)
            {
                Console.WriteLine("Test: " + test.Key);
                var dependencies = SqlAnalysis.GenerateDependenciesToObject(dependent, existingConcepts, test.Key);

                foreach (dynamic dependency in dependencies)
                {
                    Assert.AreEqual("dd", dependency.Dependent.ToString());
                }

                var actual = TestUtility.Dump(dependencies,
                                              dep => dep.GetType().Name + " " + ConceptInfoHelper.GetKeyProperties(((dynamic)dep).DependsOn));
                Assert.AreEqual(test.Value, actual, "Input: " + test.Key);
            }
        }