Skip to content

Commit 1e65a08

Browse files
authored
Baseline parser tests (#14721)
* Add parser baseline tests. * Remove ported tests. * Update FSharp.Compiler.UnitTests.fsproj * Add a newline before and after the file content. * Move original tests into designated folder. * Add ending newline to baseline files. * Take __SOURCE_DIRECTORY__ result into account. * Sanitize AST for current __SOURCE_DIRECTORY__ usage.
1 parent fd391a0 commit 1e65a08

File tree

589 files changed

+20232
-6384
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

589 files changed

+20232
-6384
lines changed

tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj

Lines changed: 1 addition & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -42,96 +42,7 @@
4242
<Compile Include="TestDoubles.fs" />
4343
<Compile Include="ConsoleOnlyOptionsTests.fs" />
4444
<Compile Include="VisualStudioVersusConsoleContextTests.fs" />
45-
<Compile Include="..\service\SyntaxTreeTests\TypeTests.fs">
46-
<Link>SyntaxTree\TypeTests.fs</Link>
47-
</Compile>
48-
<Compile Include="..\service\SyntaxTreeTests\ExpressionTests.fs">
49-
<Link>SyntaxTree\ExpressionTests.fs</Link>
50-
</Compile>
51-
<Compile Include="..\service\SyntaxTreeTests\StringTests.fs">
52-
<Link>SyntaxTree\StringTests.fs</Link>
53-
</Compile>
54-
<Compile Include="..\service\SyntaxTreeTests\ModuleOrNamespaceTests.fs">
55-
<Link>SyntaxTree\ModuleOrNamespaceTests.fs</Link>
56-
</Compile>
57-
<Compile Include="..\service\SyntaxTreeTests\ModuleOrNamespaceSigTests.fs">
58-
<Link>SyntaxTree\ModuleOrNamespaceSigTests.fs</Link>
59-
</Compile>
60-
<Compile Include="..\service\SyntaxTreeTests\SignatureTypeTests.fs">
61-
<Link>SyntaxTree\SignatureTypeTests.fs</Link>
62-
</Compile>
63-
<Compile Include="..\service\SyntaxTreeTests\MeasureTests.fs">
64-
<Link>SyntaxTree\MeasureTests.fs</Link>
65-
</Compile>
66-
<Compile Include="..\service\SyntaxTreeTests\MatchClauseTests.fs">
67-
<Link>SyntaxTree\MatchClauseTests.fs</Link>
68-
</Compile>
69-
<Compile Include="..\service\SyntaxTreeTests\SourceIdentifierTests.fs">
70-
<Link>SyntaxTree\SourceIdentifierTests.fs</Link>
71-
</Compile>
72-
<Compile Include="..\service\SyntaxTreeTests\NestedModuleTests.fs">
73-
<Link>SyntaxTree\NestedModuleTests.fs</Link>
74-
</Compile>
75-
<Compile Include="..\service\SyntaxTreeTests\BindingTests.fs">
76-
<Link>SyntaxTree\BindingTests.fs</Link>
77-
</Compile>
78-
<Compile Include="..\service\SyntaxTreeTests\ParsedHashDirectiveTests.fs">
79-
<Link>SyntaxTree\ParsedHashDirectiveTests.fs</Link>
80-
</Compile>
81-
<Compile Include="..\service\SyntaxTreeTests\LambdaTests.fs">
82-
<Link>SyntaxTree\LambdaTests.fs</Link>
83-
</Compile>
84-
<Compile Include="..\service\SyntaxTreeTests\IfThenElseTests.fs">
85-
<Link>SyntaxTree\IfThenElseTests.fs</Link>
86-
</Compile>
87-
<Compile Include="..\service\SyntaxTreeTests\UnionCaseTests.fs">
88-
<Link>SyntaxTree\UnionCaseTests.fs</Link>
89-
</Compile>
90-
<Compile Include="..\service\SyntaxTreeTests\EnumCaseTests.fs">
91-
<Link>SyntaxTree\EnumCaseTests.fs</Link>
92-
</Compile>
93-
<Compile Include="..\service\SyntaxTreeTests\PatternTests.fs">
94-
<Link>SyntaxTree\PatternTests.fs</Link>
95-
</Compile>
96-
<Compile Include="..\service\SyntaxTreeTests\ExceptionTests.fs">
97-
<Link>SyntaxTree\ExceptionTests.fs</Link>
98-
</Compile>
99-
<Compile Include="..\service\SyntaxTreeTests\MemberFlagTests.fs">
100-
<Link>SyntaxTree\MemberFlagTests.fs</Link>
101-
</Compile>
102-
<Compile Include="..\service\SyntaxTreeTests\MemberTests.fs">
103-
<Link>SyntaxTree\MemberTests.fs</Link>
104-
</Compile>
105-
<Compile Include="..\service\SyntaxTreeTests\ComputationExpressionTests.fs">
106-
<Link>SyntaxTree\ComputationExpressionTests.fs</Link>
107-
</Compile>
108-
<Compile Include="..\service\SyntaxTreeTests\ConditionalDirectiveTests.fs">
109-
<Link>SyntaxTree\ConditionalDirectiveTests.fs</Link>
110-
</Compile>
111-
<Compile Include="..\service\SyntaxTreeTests\CodeCommentTests.fs">
112-
<Link>SyntaxTree\CodeCommentTests.fs</Link>
113-
</Compile>
114-
<Compile Include="..\service\SyntaxTreeTests\OperatorNameTests.fs">
115-
<Link>SyntaxTree\OperatorNameTests.fs</Link>
116-
</Compile>
117-
<Compile Include="..\service\SyntaxTreeTests\SynIdentTests.fs">
118-
<Link>SyntaxTree\SynIdentTests.fs</Link>
119-
</Compile>
120-
<Compile Include="..\service\SyntaxTreeTests\SynTypeTests.fs">
121-
<Link>SyntaxTree\SynTypeTests.fs</Link>
122-
</Compile>
123-
<Compile Include="..\service\SyntaxTreeTests\AttributeTests.fs">
124-
<Link>SyntaxTree\AttributeTests.fs</Link>
125-
</Compile>
126-
<Compile Include="..\service\SyntaxTreeTests\ExternTests.fs">
127-
<Link>SyntaxTree\ExternTests.fs</Link>
128-
</Compile>
129-
<Compile Include="..\service\SyntaxTreeTests\LeadingKeywordTests.fs">
130-
<Link>SyntaxTree\LeadingKeywordTests.fs</Link>
131-
</Compile>
132-
<Compile Include="..\service\SyntaxTreeTests\ValTests.fs">
133-
<Link>SyntaxTree\ValTests.fs</Link>
134-
</Compile>
45+
<Compile Include="..\service\SyntaxTreeTests.fs" />
13546
<Compile Include="..\service\FileSystemTests.fs">
13647
<Link>FileSystemTests.fs</Link>
13748
</Compile>

tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -36,75 +36,7 @@
3636
<Compile Include="..\..\tests\service\Symbols.fs">
3737
<Link>CompilerService\Symbols.fs</Link>
3838
</Compile>
39-
<Compile Include="..\..\tests\service\SyntaxTreeTests\TypeTests.fs">
40-
<Link>SyntaxTree\TypeTests.fs</Link>
41-
</Compile>
42-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ExpressionTests.fs">
43-
<Link>SyntaxTree\ExpressionTests.fs</Link>
44-
</Compile>
45-
<Compile Include="..\..\tests\service\SyntaxTreeTests\StringTests.fs">
46-
<Link>SyntaxTree\StringTests.fs</Link>
47-
</Compile>
48-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ModuleOrNamespaceTests.fs">
49-
<Link>SyntaxTree\ModuleOrNamespaceTests.fs</Link>
50-
</Compile>
51-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ModuleOrNamespaceSigTests.fs">
52-
<Link>SyntaxTree\ModuleOrNamespaceSigTests.fs</Link>
53-
</Compile>
54-
<Compile Include="..\..\tests\service\SyntaxTreeTests\SignatureTypeTests.fs">
55-
<Link>SyntaxTree\SignatureTypeTests.fs</Link>
56-
</Compile>
57-
<Compile Include="..\..\tests\service\SyntaxTreeTests\MeasureTests.fs">
58-
<Link>SyntaxTree\MeasureTests.fs</Link>
59-
</Compile>
60-
<Compile Include="..\..\tests\service\SyntaxTreeTests\MatchClauseTests.fs">
61-
<Link>SyntaxTree\MatchClauseTests.fs</Link>
62-
</Compile>
63-
<Compile Include="..\..\tests\service\SyntaxTreeTests\SourceIdentifierTests.fs">
64-
<Link>SyntaxTree\SourceIdentifierTests.fs</Link>
65-
</Compile>
66-
<Compile Include="..\..\tests\service\SyntaxTreeTests\NestedModuleTests.fs">
67-
<Link>SyntaxTree\NestedModuleTests.fs</Link>
68-
</Compile>
69-
<Compile Include="..\..\tests\service\SyntaxTreeTests\BindingTests.fs">
70-
<Link>SyntaxTree\BindingTests.fs</Link>
71-
</Compile>
72-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ParsedHashDirectiveTests.fs">
73-
<Link>SyntaxTree\ParsedHashDirectiveTests.fs</Link>
74-
</Compile>
75-
<Compile Include="..\..\tests\service\SyntaxTreeTests\LambdaTests.fs">
76-
<Link>SyntaxTree\LambdaTests.fs</Link>
77-
</Compile>
78-
<Compile Include="..\..\tests\service\SyntaxTreeTests\IfThenElseTests.fs">
79-
<Link>SyntaxTree\IfThenElseTests.fs</Link>
80-
</Compile>
81-
<Compile Include="..\..\tests\service\SyntaxTreeTests\UnionCaseTests.fs">
82-
<Link>SyntaxTree\UnionCaseTests.fs</Link>
83-
</Compile>
84-
<Compile Include="..\..\tests\service\SyntaxTreeTests\EnumCaseTests.fs">
85-
<Link>SyntaxTree\EnumCaseTests.fs</Link>
86-
</Compile>
87-
<Compile Include="..\..\tests\service\SyntaxTreeTests\PatternTests.fs">
88-
<Link>SyntaxTree\PatternTests.fs</Link>
89-
</Compile>
90-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ExceptionTests.fs">
91-
<Link>SyntaxTree\ExceptionTests.fs</Link>
92-
</Compile>
93-
<Compile Include="..\..\tests\service\SyntaxTreeTests\MemberFlagTests.fs">
94-
<Link>SyntaxTree\MemberFlagTests.fs</Link>
95-
</Compile>
96-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ComputationExpressionTests.fs">
97-
<Link>SyntaxTree\ComputationExpressionTests.fs</Link>
98-
</Compile>
99-
<Compile Include="..\..\tests\service\SyntaxTreeTests\ConditionalDirectiveTests.fs">
100-
<Link>SyntaxTree\ConditionalDirectiveTests.fs</Link>
101-
</Compile>
102-
<Compile Include="..\..\tests\service\SyntaxTreeTests\CodeCommentTests.fs">
103-
<Link>SyntaxTree\CodeCommentTests.fs</Link>
104-
</Compile>
105-
<Compile Include="..\..\tests\service\SyntaxTreeTests\OperatorNameTests.fs">
106-
<Link>SyntaxTree\OperatorNameTests.fs</Link>
107-
</Compile>
39+
<Compile Include="..\..\tests\service\SyntaxTreeTests.fs" />
10840
<Compile Include="..\..\tests\service\EditorTests.fs">
10941
<Link>CompilerService\EditorTests.fs</Link>
11042
</Compile>

tests/service/SyntaxTreeTests.fs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
module Tests.Service.SyntaxTree
2+
3+
open System.IO
4+
open FSharp.Compiler.CodeAnalysis
5+
open FSharp.Compiler.Service.Tests.Common
6+
open FSharp.Compiler.Syntax
7+
open FSharp.Compiler.Text
8+
open NUnit.Framework
9+
10+
let testCasesDir = Path.Combine(__SOURCE_DIRECTORY__, "data", "SyntaxTree")
11+
12+
let allTestCases =
13+
Directory.EnumerateFiles(testCasesDir, "*.fs?", SearchOption.AllDirectories)
14+
|> Seq.map (fun f ->
15+
let fileInfo = FileInfo(f)
16+
let fileName = Path.Combine(fileInfo.Directory.Name, fileInfo.Name)
17+
[| fileName :> obj |])
18+
|> Seq.toArray
19+
20+
[<Literal>]
21+
let RootDirectory = @"/root"
22+
23+
/// <summary>
24+
/// Everytime `__SOURCE_DIRECTORY__` was used in the code, the ast will contain an invalid value and range for it.
25+
/// This should be cleaned up when the test runs during CI/CD.
26+
/// </summary>
27+
/// <remarks>
28+
/// This function is incomplete and does not clean up the entire ParsedInput.
29+
/// A shortcut was made to only support the existing use-cases.
30+
/// </remarks>
31+
let private sanitizeAST (sourceDirectoryValue: string) (ast: ParsedInput) : ParsedInput =
32+
let isZero (m: range) =
33+
m.StartLine = 0 && m.StartColumn = 0 && m.EndLine = 0 && m.EndColumn = 0
34+
35+
// __SOURCE_DIRECTORY__ will contain the evaluated value, so we want to replace it with a stable value instead.
36+
let mapParsedHashDirective (ParsedHashDirective(ident, args, _) as phd) =
37+
match args with
38+
| [ ParsedHashDirectiveArgument.SourceIdentifier("__SOURCE_DIRECTORY__", _, mSourceDirectory) ] ->
39+
let mZero =
40+
Range.mkRange mSourceDirectory.FileName (Position.mkPos 0 0) (Position.mkPos 0 0)
41+
42+
ParsedHashDirective(
43+
ident,
44+
[ ParsedHashDirectiveArgument.SourceIdentifier("__SOURCE_DIRECTORY__", sourceDirectoryValue, mZero) ],
45+
mZero
46+
)
47+
| _ -> phd
48+
49+
let (|SourceDirectoryConstant|_|) (constant: SynConst) =
50+
match constant with
51+
| SynConst.SourceIdentifier("__SOURCE_DIRECTORY__", _, mSourceDirectory) ->
52+
let mZero =
53+
Range.mkRange mSourceDirectory.FileName (Position.mkPos 0 0) (Position.mkPos 0 0)
54+
55+
Some(SynConst.SourceIdentifier("__SOURCE_DIRECTORY__", sourceDirectoryValue, mZero), mZero)
56+
| _ -> None
57+
58+
let (|SourceDirectoryConstantExpr|_|) (expr: SynExpr) =
59+
match expr with
60+
| SynExpr.Const(SourceDirectoryConstant(constant, mZero), _) -> Some(SynExpr.Const(constant, mZero))
61+
| _ -> None
62+
63+
let rec mapSynModuleDecl (mdl: SynModuleDecl) =
64+
match mdl with
65+
| SynModuleDecl.HashDirective(ParsedHashDirective(range = mZero) as hd, m) ->
66+
let hd = mapParsedHashDirective hd
67+
// Only update the range of SynModuleSigDecl.HashDirective if the value was updated.
68+
let m = if isZero mZero then mZero else m
69+
SynModuleDecl.HashDirective(hd, m)
70+
| SynModuleDecl.NestedModule(moduleInfo, isRecursive, decls, isContinuing, range, trivia) ->
71+
SynModuleDecl.NestedModule(moduleInfo, isRecursive, List.map mapSynModuleDecl decls, isContinuing, range, trivia)
72+
| SynModuleDecl.Expr(SourceDirectoryConstantExpr(expr), _) -> SynModuleDecl.Expr(expr, expr.Range)
73+
| _ -> mdl
74+
75+
let mapSynModuleOrNamespace (SynModuleOrNamespace(longId, isRecursive, kind, decls, xmlDoc, attribs, ao, range, trivia)) =
76+
SynModuleOrNamespace(longId, isRecursive, kind, List.map mapSynModuleDecl decls, xmlDoc, attribs, ao, range, trivia)
77+
78+
let rec mapSynModuleDeclSig (msdl: SynModuleSigDecl) =
79+
match msdl with
80+
| SynModuleSigDecl.HashDirective(ParsedHashDirective(range = mZero) as hd, m) ->
81+
let hd = mapParsedHashDirective hd
82+
// Only update the range of SynModuleSigDecl.HashDirective if the value was updated.
83+
let m = if isZero mZero then mZero else m
84+
SynModuleSigDecl.HashDirective(hd, m)
85+
| SynModuleSigDecl.NestedModule(moduleInfo, isRecursive, decls, range, trivia) ->
86+
SynModuleSigDecl.NestedModule(moduleInfo, isRecursive, List.map mapSynModuleDeclSig decls, range, trivia)
87+
| _ -> msdl
88+
89+
let mapSynModuleOrNamespaceSig (SynModuleOrNamespaceSig(longId, isRecursive, kind, decls, xmlDoc, attribs, ao, range, trivia)) =
90+
SynModuleOrNamespaceSig(longId, isRecursive, kind, List.map mapSynModuleDeclSig decls, xmlDoc, attribs, ao, range, trivia)
91+
92+
match ast with
93+
| ParsedInput.ImplFile(ParsedImplFileInput(fileName,
94+
isScript,
95+
qualifiedNameOfFile,
96+
scopedPragmas,
97+
hashDirectives,
98+
contents,
99+
flags,
100+
trivia,
101+
identifiers)) ->
102+
ParsedImplFileInput(
103+
fileName,
104+
isScript,
105+
qualifiedNameOfFile,
106+
scopedPragmas,
107+
List.map mapParsedHashDirective hashDirectives,
108+
List.map mapSynModuleOrNamespace contents,
109+
flags,
110+
trivia,
111+
identifiers
112+
)
113+
|> ParsedInput.ImplFile
114+
| ParsedInput.SigFile(ParsedSigFileInput(fileName, qualifiedNameOfFile, scopedPragmas, hashDirectives, contents, trivia, identifiers)) ->
115+
ParsedSigFileInput(
116+
fileName,
117+
qualifiedNameOfFile,
118+
scopedPragmas,
119+
List.map mapParsedHashDirective hashDirectives,
120+
List.map mapSynModuleOrNamespaceSig contents,
121+
trivia,
122+
identifiers
123+
)
124+
|> ParsedInput.SigFile
125+
126+
let parseSourceCode (name: string, code: string) =
127+
let location = Path.Combine(RootDirectory, name).Replace("\\", "/")
128+
129+
let parseResults =
130+
checker.ParseFile(
131+
location,
132+
SourceText.ofString code,
133+
{ FSharpParsingOptions.Default with
134+
SourceFiles = [| location |] }
135+
)
136+
|> Async.RunImmediate
137+
138+
let tree = parseResults.ParseTree
139+
let sourceDirectoryValue = $"{RootDirectory}/{FileInfo(location).Directory.Name}"
140+
sanitizeAST sourceDirectoryValue tree
141+
142+
/// Asserts the parsed untyped tree matches the expected baseline.
143+
///
144+
/// To update a baseline:
145+
/// CMD: set TEST_UPDATE_BSL=1 & dotnet test --filter "ParseFile"
146+
/// PowerShell: $env:TEST_UPDATE_BSL = "1" ; dotnet test --filter "ParseFile"
147+
/// Linux/macOS: export TEST_UPDATE_BSL=1 & dotnet test --filter "ParseFile"
148+
///
149+
/// Assuming your current directory is tests/FSharp.Compiler.Service.Tests
150+
[<TestCaseSource(nameof allTestCases)>]
151+
let ParseFile fileName =
152+
let fullPath = Path.Combine(testCasesDir, fileName)
153+
let contents = File.ReadAllText fullPath
154+
let ast = parseSourceCode (fileName, contents)
155+
let normalize (s: string) = s.Replace("\r", "")
156+
let actual = sprintf "%A" ast |> normalize |> sprintf "%s\n"
157+
let bslPath = $"{fullPath}.bsl"
158+
159+
let expected =
160+
if File.Exists bslPath then
161+
File.ReadAllText bslPath |> normalize
162+
else
163+
"No baseline was found"
164+
165+
let testUpdateBSLEnv = System.Environment.GetEnvironmentVariable("TEST_UPDATE_BSL")
166+
167+
if not (isNull testUpdateBSLEnv) && testUpdateBSLEnv.Trim() = "1" then
168+
File.WriteAllText(bslPath, actual)
169+
170+
Assert.AreEqual(expected, actual)

tests/service/SyntaxTreeTests/AttributeTests.fs

Lines changed: 0 additions & 50 deletions
This file was deleted.

0 commit comments

Comments
 (0)