Skip to content

Commit 0a2211f

Browse files
Support write back of expected AST to json (#203)
Co-authored-by: Sébastien Ros <[email protected]>
1 parent d6cc2ba commit 0a2211f

File tree

1 file changed

+215
-176
lines changed

1 file changed

+215
-176
lines changed

test/Esprima.Tests/Fixtures.cs

Lines changed: 215 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,215 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.IO;
4-
using System.Linq;
5-
using System.Reflection;
6-
using Esprima.Ast;
7-
using Esprima.Utils;
8-
using Newtonsoft.Json.Linq;
9-
using Xunit;
10-
11-
namespace Esprima.Test
12-
{
13-
public class Fixtures
14-
{
15-
[Fact]
16-
public void HoistingScopeShouldWork()
17-
{
18-
var parser = new JavaScriptParser(@"
19-
function p() {}
20-
var x;");
21-
var program = parser.ParseScript();
22-
}
23-
24-
private static string ParseAndFormat(SourceType sourceType, string source, ParserOptions options)
25-
{
26-
var parser = new JavaScriptParser(source, options);
27-
var program = sourceType == SourceType.Script ? (Program) parser.ParseScript() : parser.ParseModule();
28-
const string indent = " ";
29-
return program.ToJsonString(
30-
AstJson.Options.Default
31-
.WithIncludingLineColumn(true)
32-
.WithIncludingRange(true),
33-
indent
34-
);
35-
}
36-
37-
private static void CompareTrees(string actual, string expected, string path)
38-
{
39-
var actualJObject = JObject.Parse(actual);
40-
var expectedJObject = JObject.Parse(expected);
41-
42-
// Don't compare the tokens array as it's not in the generated AST
43-
expectedJObject.Remove("tokens");
44-
expectedJObject.Remove("comments");
45-
expectedJObject.Remove("errors");
46-
47-
var areEqual = JToken.DeepEquals(actualJObject, expectedJObject);
48-
if (!areEqual)
49-
{
50-
var actualString = actualJObject.ToString();
51-
var expectedString = expectedJObject.ToString();
52-
Assert.Equal(expectedString, actualString);
53-
}
54-
}
55-
56-
[Theory]
57-
[MemberData(nameof(SourceFiles), "Fixtures")]
58-
public void ExecuteTestCase(string fixture)
59-
{
60-
var options = new ParserOptions { Tokens = true };
61-
62-
string treeFilePath, failureFilePath, moduleFilePath;
63-
var jsFilePath = Path.Combine(GetFixturesPath(), "Fixtures", fixture);
64-
if (jsFilePath.EndsWith(".source.js"))
65-
{
66-
treeFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".tree.json";
67-
failureFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".failure.json";
68-
moduleFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".module.json";
69-
}
70-
else
71-
{
72-
treeFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".tree.json";
73-
failureFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".failure.json";
74-
moduleFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".module.json";
75-
}
76-
77-
var script = File.ReadAllText(jsFilePath);
78-
if (jsFilePath.EndsWith(".source.js"))
79-
{
80-
var parser = new JavaScriptParser(script);
81-
var program = parser.ParseScript();
82-
var source = program.Body.First().As<VariableDeclaration>().Declarations.First().As<VariableDeclarator>().Init.As<Literal>().StringValue;
83-
script = source;
84-
}
85-
86-
var expected = "";
87-
var invalid = false;
88-
89-
var filename = Path.GetFileNameWithoutExtension(jsFilePath);
90-
91-
var isModule =
92-
filename.Contains("module") ||
93-
filename.Contains("export") ||
94-
filename.Contains("import");
95-
96-
if (!filename.Contains(".module"))
97-
{
98-
isModule &= !jsFilePath.Contains("dynamic-import") && !jsFilePath.Contains("script");
99-
}
100-
101-
var sourceType = isModule
102-
? SourceType.Module
103-
: SourceType.Script;
104-
105-
if (File.Exists(moduleFilePath))
106-
{
107-
sourceType = SourceType.Module;
108-
expected = File.ReadAllText(moduleFilePath);
109-
}
110-
else if (File.Exists(treeFilePath))
111-
{
112-
expected = File.ReadAllText(treeFilePath);
113-
}
114-
else if (File.Exists(failureFilePath))
115-
{
116-
invalid = true;
117-
expected = File.ReadAllText(failureFilePath);
118-
}
119-
else
120-
{
121-
// cannot compare
122-
return;
123-
}
124-
125-
invalid |=
126-
filename.Contains("error") ||
127-
filename.Contains("invalid") && !filename.Contains("invalid-yield-object-");
128-
129-
if (!invalid)
130-
{
131-
options.Tolerant = true;
132-
133-
var actual = ParseAndFormat(sourceType, script, options);
134-
CompareTrees(actual, expected, jsFilePath);
135-
}
136-
else
137-
{
138-
options.Tolerant = false;
139-
140-
// TODO: check the accuracy of the message and of the location
141-
Assert.Throws<ParserException>(() => ParseAndFormat(sourceType, script, options));
142-
}
143-
}
144-
145-
public static IEnumerable<object[]> SourceFiles(string relativePath)
146-
{
147-
var fixturesPath = Path.Combine(GetFixturesPath(), relativePath);
148-
149-
var files = Directory.GetFiles(fixturesPath, "*.js", SearchOption.AllDirectories);
150-
151-
return files
152-
.Select(x => new object[] { x.Substring(fixturesPath.Length + 1) })
153-
.ToList();
154-
}
155-
156-
internal static string GetFixturesPath()
157-
{
158-
var assemblyPath = new Uri(typeof(Fixtures).GetTypeInfo().Assembly.CodeBase).LocalPath;
159-
var assemblyDirectory = new FileInfo(assemblyPath).Directory;
160-
161-
var root = assemblyDirectory.Parent.Parent.Parent.FullName;
162-
return root;
163-
}
164-
165-
[Fact]
166-
public void CommentsAreParsed()
167-
{
168-
var count = 0;
169-
Action<Node> action = node => count++;
170-
var parser = new JavaScriptParser("// this is a comment", new ParserOptions(), action);
171-
parser.ParseScript();
172-
173-
Assert.Equal(1, count);
174-
}
175-
}
176-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using Esprima.Ast;
7+
using Esprima.Utils;
8+
using Newtonsoft.Json.Linq;
9+
using Xunit;
10+
11+
namespace Esprima.Test
12+
{
13+
public class Fixtures
14+
{
15+
// Do manually set it to true to update local test files with the current results.
16+
// Only use this when the test is deemed wrong.
17+
const bool WriteBackExpectedTree = false;
18+
19+
[Fact]
20+
public void HoistingScopeShouldWork()
21+
{
22+
var parser = new JavaScriptParser(@"
23+
function p() {}
24+
var x;");
25+
var program = parser.ParseScript();
26+
}
27+
28+
private static string ParseAndFormat(SourceType sourceType, string source, ParserOptions options)
29+
{
30+
var parser = new JavaScriptParser(source, options);
31+
var program = sourceType == SourceType.Script ? (Program) parser.ParseScript() : parser.ParseModule();
32+
const string indent = " ";
33+
return program.ToJsonString(
34+
AstJson.Options.Default
35+
.WithIncludingLineColumn(true)
36+
.WithIncludingRange(true),
37+
indent
38+
);
39+
}
40+
41+
private static bool CompareTreesInternal(string actual, string expected)
42+
{
43+
var actualJObject = JObject.Parse(actual);
44+
var expectedJObject = JObject.Parse(expected);
45+
46+
// Don't compare the tokens array as it's not in the generated AST
47+
expectedJObject.Remove("tokens");
48+
expectedJObject.Remove("comments");
49+
expectedJObject.Remove("errors");
50+
51+
return JToken.DeepEquals(actualJObject, expectedJObject);
52+
}
53+
54+
private static void CompareTrees(string actual, string expected, string path)
55+
{
56+
var actualJObject = JObject.Parse(actual);
57+
var expectedJObject = JObject.Parse(expected);
58+
59+
// Don't compare the tokens array as it's not in the generated AST
60+
expectedJObject.Remove("tokens");
61+
expectedJObject.Remove("comments");
62+
expectedJObject.Remove("errors");
63+
64+
var areEqual = JToken.DeepEquals(actualJObject, expectedJObject);
65+
if (!areEqual)
66+
{
67+
var actualString = actualJObject.ToString();
68+
var expectedString = expectedJObject.ToString();
69+
Assert.Equal(expectedString, actualString);
70+
}
71+
}
72+
73+
[Theory]
74+
[MemberData(nameof(SourceFiles), "Fixtures")]
75+
public void ExecuteTestCase(string fixture)
76+
{
77+
78+
var options = new ParserOptions { Tokens = true };
79+
80+
string treeFilePath, failureFilePath, moduleFilePath;
81+
var jsFilePath = Path.Combine(GetFixturesPath(), "Fixtures", fixture);
82+
if (jsFilePath.EndsWith(".source.js"))
83+
{
84+
treeFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".tree.json";
85+
failureFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".failure.json";
86+
moduleFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(jsFilePath))) + ".module.json";
87+
}
88+
else
89+
{
90+
treeFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".tree.json";
91+
failureFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".failure.json";
92+
moduleFilePath = Path.Combine(Path.GetDirectoryName(jsFilePath), Path.GetFileNameWithoutExtension(jsFilePath)) + ".module.json";
93+
}
94+
95+
var script = File.ReadAllText(jsFilePath);
96+
if (jsFilePath.EndsWith(".source.js"))
97+
{
98+
var parser = new JavaScriptParser(script);
99+
var program = parser.ParseScript();
100+
var source = program.Body.First().As<VariableDeclaration>().Declarations.First().As<VariableDeclarator>().Init.As<Literal>().StringValue;
101+
script = source;
102+
}
103+
104+
var expected = "";
105+
var invalid = false;
106+
107+
var filename = Path.GetFileNameWithoutExtension(jsFilePath);
108+
109+
var isModule =
110+
filename.Contains("module") ||
111+
filename.Contains("export") ||
112+
filename.Contains("import");
113+
114+
if (!filename.Contains(".module"))
115+
{
116+
isModule &= !jsFilePath.Contains("dynamic-import") && !jsFilePath.Contains("script");
117+
}
118+
119+
var sourceType = isModule
120+
? SourceType.Module
121+
: SourceType.Script;
122+
123+
#pragma warning disable 162
124+
if (File.Exists(moduleFilePath))
125+
{
126+
sourceType = SourceType.Module;
127+
expected = File.ReadAllText(moduleFilePath);
128+
if (WriteBackExpectedTree)
129+
{
130+
var actual = ParseAndFormat(sourceType, script, options);
131+
if (!CompareTreesInternal(actual, expected))
132+
File.WriteAllText(moduleFilePath, actual);
133+
}
134+
}
135+
else if (File.Exists(treeFilePath))
136+
{
137+
expected = File.ReadAllText(treeFilePath);
138+
if (WriteBackExpectedTree)
139+
140+
{
141+
var actual = ParseAndFormat(sourceType, script, options);
142+
if (!CompareTreesInternal(actual, expected))
143+
File.WriteAllText(treeFilePath, actual);
144+
}
145+
}
146+
else if (File.Exists(failureFilePath))
147+
{
148+
invalid = true;
149+
expected = File.ReadAllText(failureFilePath);
150+
if (WriteBackExpectedTree)
151+
{
152+
var actual = ParseAndFormat(sourceType, script, options);
153+
if (!CompareTreesInternal(actual, expected))
154+
File.WriteAllText(failureFilePath, actual);
155+
}
156+
#pragma warning restore 162
157+
}
158+
else
159+
{
160+
// cannot compare
161+
return;
162+
}
163+
164+
invalid |=
165+
filename.Contains("error") ||
166+
filename.Contains("invalid") && !filename.Contains("invalid-yield-object-");
167+
168+
if (!invalid)
169+
{
170+
options.Tolerant = true;
171+
172+
var actual = ParseAndFormat(sourceType, script, options);
173+
CompareTrees(actual, expected, jsFilePath);
174+
}
175+
else
176+
{
177+
options.Tolerant = false;
178+
179+
// TODO: check the accuracy of the message and of the location
180+
Assert.Throws<ParserException>(() => ParseAndFormat(sourceType, script, options));
181+
}
182+
}
183+
184+
public static IEnumerable<object[]> SourceFiles(string relativePath)
185+
{
186+
var fixturesPath = Path.Combine(GetFixturesPath(), relativePath);
187+
188+
var files = Directory.GetFiles(fixturesPath, "*.js", SearchOption.AllDirectories);
189+
190+
return files
191+
.Select(x => new object[] { x.Substring(fixturesPath.Length + 1) })
192+
.ToList();
193+
}
194+
195+
internal static string GetFixturesPath()
196+
{
197+
var assemblyPath = new Uri(typeof(Fixtures).GetTypeInfo().Assembly.CodeBase).LocalPath;
198+
var assemblyDirectory = new FileInfo(assemblyPath).Directory;
199+
200+
var root = assemblyDirectory.Parent.Parent.Parent.FullName;
201+
return root;
202+
}
203+
204+
[Fact]
205+
public void CommentsAreParsed()
206+
{
207+
var count = 0;
208+
Action<Node> action = node => count++;
209+
var parser = new JavaScriptParser("// this is a comment", new ParserOptions(), action);
210+
parser.ParseScript();
211+
212+
Assert.Equal(1, count);
213+
}
214+
}
215+
}

0 commit comments

Comments
 (0)