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); } }
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); } }
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); }
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."); } }
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); }
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); } }