Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/NUglify.Tests/App.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.1.1.3" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
17 changes: 17 additions & 0 deletions src/NUglify.Tests/JavaScript/AllJavascriptSyntaxTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using NUglify.Tests.JavaScript.Common;
using NUnit.Framework;

namespace NUglify.Tests.JavaScript
{
[TestFixture]
public class AllJavascriptSyntaxTest
{
/// <summary>
/// check all possible files in input-directory for syntax errors after minification
/// </summary>
[Test]
public void SyntaxTestForAllFilesLineBreaks() {
TestHelper.Instance.RunSyntaxTestForAllFilesLineBreaks();
}
}
}
111 changes: 111 additions & 0 deletions src/NUglify.Tests/JavaScript/Common/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;
using NUglify.JavaScript;
using NUglify.JavaScript.Visitors;
using NUnit.Framework;
Expand Down Expand Up @@ -700,6 +704,113 @@ public void RunErrorTest(params JSError[] expectedErrorArray)
RunErrorTest(string.Empty, expectedErrorArray);
}

/// <summary>
/// check all files in input-directory for syntax errors after minification
/// execute javascript in V8 engine
/// each file that starts successfully without minification will be rerun after minification.
/// in some cases minifier generate endless running code. Example: D:\Git2\NUglify\src\NUglify.Tests\bin\Debug\TestData\JS\Input\ES2015\GeneratorFunction.js
/// </summary>
/// <exception cref="AggregateException"></exception>
public void RunSyntaxTestForAllFilesLineBreaks() {
DirectoryInfo dir = new DirectoryInfo(InputFolder);
List<FileInfo> allTestFiles = dir.GetFiles("*.js", SearchOption.AllDirectories).ToList();
var sw = new Stopwatch();
sw.Start();
var timeout = TimeSpan.FromSeconds(2);
var testResults = allTestFiles.Select(fi => {
string jsSource = File.ReadAllText(fi.FullName);
var (debugFinished, debugExecutionStarted, _) = Execute(jsSource, fi.Name, "debug", sw, timeout);
if (!debugExecutionStarted) {
Trace.WriteLine($"{fi.Name}: Syntax error, skipping minification ({fi.FullName}).");
return null;
} else {
var crunchedCode = Minify(jsSource, "-line:1");
var (minifiedFinished, minifiedExecutionStarted, minifiedException) = Execute(crunchedCode, fi.Name, "minified", sw, timeout);
if (!minifiedExecutionStarted) {
//There
Assert.NotNull(minifiedException, "There should be an exception if the execution did not even start.");
return new {
testPassed = false,
message = minifiedException.ErrorDetails,
filePath = fi.FullName,
minifiedContent = crunchedCode
};
} else if (!minifiedFinished && debugFinished) {
//Timeout in minified code, but not in original.
return new {
testPassed = false,
message = "Timeout in minified code, but not in original",
filePath = fi.FullName,
minifiedContent = crunchedCode
};
} else {
return null;
}
}
}).Where(r => r != null).ToList();

if (testResults.Any()) {
throw new Exception("Test failed, following files had errors." + Environment.NewLine + String.Join(Environment.NewLine, testResults.Select(f => $"{f.filePath} => {f.message}{Environment.NewLine}{f.minifiedContent}{Environment.NewLine}")));
}
}

private static String Minify(string code, string minifyParameters) {
var switchParser = new UglifyCommandParser();
switchParser.Parse(minifyParameters);

var sb = new StringBuilder();
var parser = new JSParser();
using (var writer = new StringWriter(sb)) {
if (switchParser.JSSettings.PreprocessOnly) {
parser.EchoWriter = writer;
}
// normal -- just run it through the parser
var block = parser.Parse(new DocumentContext(code), switchParser.JSSettings);
if (!switchParser.JSSettings.PreprocessOnly) {
// look at the settings for the proper output visitor
if (switchParser.JSSettings.Format == JavaScriptFormat.JSON) {
{
if (!JsonOutputVisitor.Apply(writer, block, switchParser.JSSettings)) {
Trace.WriteLine("JSON OUTPUT ERRORS!");
}
}
} else {
OutputVisitor.Apply(writer, block, switchParser.JSSettings);
}
}
}
return sb.ToString();
}

private (bool, bool, ScriptEngineException) Execute(string code, string filename, string type, Stopwatch sw, TimeSpan timeout) {
var engine = new V8ScriptEngine();
bool executionStarted = false;
ScriptEngineException exception = null;
var task = Task.Run(() => {
try {
Trace.WriteLine($"{sw.ElapsedMilliseconds}: Starting {filename}.{type}.");
engine.Execute(code);
Trace.WriteLine($"{sw.ElapsedMilliseconds}: Finished {filename}.{type}.");
executionStarted = true;
} catch (ScriptEngineException e) {
exception = e;
if (e.ExecutionStarted) {
executionStarted = true;
Trace.WriteLine($"{sw.ElapsedMilliseconds}: Exception from {filename}.{type}. Execution did start.");
} else {
Trace.WriteLine($"{sw.ElapsedMilliseconds}: Exception from {filename}.{type}. Execution did not even start.");
}
}
});
bool finishedInTime = task.Wait(timeout);
if (!finishedInTime) {
//If a timeout occurs, we do just assume that the execution started.
executionStarted = true;
}
Assert.IsTrue(executionStarted || exception != null, "There should be an exception if the execution did not even start.");
return (finishedInTime, executionStarted, exception);
}

public void RunErrorTest(string settingsSwitches, params JSError[] expectedErrorArray)
{
// open the stack trace for this call
Expand Down
48 changes: 47 additions & 1 deletion src/NUglify.Tests/NUglify.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.ClearScript.V8.Native.win-x86.7.3.1\build\Microsoft.ClearScript.V8.Native.win-x86.props" Condition="Exists('..\packages\Microsoft.ClearScript.V8.Native.win-x86.7.3.1\build\Microsoft.ClearScript.V8.Native.win-x86.props')" />
<Import Project="..\packages\Microsoft.ClearScript.V8.Native.win-x64.7.3.1\build\Microsoft.ClearScript.V8.Native.win-x64.props" Condition="Exists('..\packages\Microsoft.ClearScript.V8.Native.win-x64.7.3.1\build\Microsoft.ClearScript.V8.Native.win-x64.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
Expand Down Expand Up @@ -43,13 +45,55 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="ClearScript.Core, Version=7.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ClearScript.Core.7.3.1\lib\net45\ClearScript.Core.dll</HintPath>
</Reference>
<Reference Include="ClearScript.V8, Version=7.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ClearScript.V8.7.3.1\lib\net45\ClearScript.V8.dll</HintPath>
</Reference>
<Reference Include="ClearScript.V8.ICUData, Version=7.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ClearScript.V8.ICUData.7.3.1\lib\netstandard1.0\ClearScript.V8.ICUData.dll</HintPath>
</Reference>
<Reference Include="ClearScript.Windows, Version=7.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ClearScript.Windows.7.3.1\lib\net45\ClearScript.Windows.dll</HintPath>
</Reference>
<Reference Include="ClearScript.Windows.Core, Version=7.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ClearScript.Windows.Core.7.3.1\lib\net45\ClearScript.Windows.Core.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -98,6 +142,7 @@
<Compile Include="Html\TestCollapseWhiteSpaces.cs" />
<Compile Include="Html\TestScripts.cs" />
<Compile Include="Html\TestStyles.cs" />
<Compile Include="JavaScript\AllJavascriptSyntaxTest.cs" />
<Compile Include="JavaScript\ArrayHandling.cs" />
<Compile Include="JavaScript\AspNet.cs" />
<Compile Include="JavaScript\Assignments.cs" />
Expand Down Expand Up @@ -166,6 +211,7 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="project.json" />
<Content Include="TestData\Core\Expected\NUglifyTask\Combined.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
6 changes: 6 additions & 0 deletions src/NUglify.Tests/NUglify.Tests.nuget.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.clearscript.v8.native.win-x86\7.3.1\build\Microsoft.ClearScript.V8.Native.win-x86.props" Condition="Exists('$(NuGetPackageRoot)microsoft.clearscript.v8.native.win-x86\7.3.1\build\Microsoft.ClearScript.V8.Native.win-x86.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.clearscript.v8.native.win-x64\7.3.1\build\Microsoft.ClearScript.V8.Native.win-x64.props" Condition="Exists('$(NuGetPackageRoot)microsoft.clearscript.v8.native.win-x64\7.3.1\build\Microsoft.ClearScript.V8.Native.win-x64.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgNUnit3TestAdapter Condition=" '$(PkgNUnit3TestAdapter)' == '' ">C:\Users\Andrew Bullock\.nuget\packages\nunit3testadapter\3.5.0</PkgNUnit3TestAdapter>
<PkgMicrosoft_ClearScript_V8_Native_win-x86 Condition=" '$(PkgMicrosoft_ClearScript_V8_Native_win-x86)' == '' ">C:\Users\Andrew Bullock\.nuget\packages\microsoft.clearscript.v8.native.win-x86\7.3.1</PkgMicrosoft_ClearScript_V8_Native_win-x86>
<PkgMicrosoft_ClearScript_V8_Native_win-x64 Condition=" '$(PkgMicrosoft_ClearScript_V8_Native_win-x64)' == '' ">C:\Users\Andrew Bullock\.nuget\packages\microsoft.clearscript.v8.native.win-x64\7.3.1</PkgMicrosoft_ClearScript_V8_Native_win-x64>
</PropertyGroup>
</Project>
26 changes: 26 additions & 0 deletions src/NUglify.Tests/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Esprima" version="3.0.0-beta-3" targetFramework="net461" />
<package id="Jint" version="3.0.0-beta-2039" targetFramework="net461" />
<package id="Microsoft.ClearScript" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.Core" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.V8" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.V8.ICUData" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.V8.Native.win-x64" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.V8.Native.win-x86" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.Windows" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.ClearScript.Windows.Core" version="7.3.1" targetFramework="net461" />
<package id="NUnit" version="3.5.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net461" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
</packages>
3 changes: 2 additions & 1 deletion src/NUglify.Tests/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"dependencies": {
"NUnit": "3.5.0",
"NUnit3TestAdapter": "3.5.0"
"NUnit3TestAdapter": "3.5.0",
"Microsoft.ClearScript": "7.3.1"
}
}
15 changes: 11 additions & 4 deletions src/NUglify/JavaScript/Visitors/OutputVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ public void Visit(CallExpression node)
{
if (node.OptionalChaining)
{
OutputPossibleLineBreak('?');
Output('?');
OutputPossibleLineBreak('.');
}

Expand Down Expand Up @@ -2549,7 +2549,7 @@ public void Visit(MemberExpression node)
}

if (node.OptionalChaining)
OutputPossibleLineBreak('?');
Output('?');
OutputPossibleLineBreak('.');

MarkSegment(node, node.Name, node.NameContext);
Expand Down Expand Up @@ -3985,15 +3985,22 @@ void OutputFunctionArgsAndBody(FunctionObject node)
Unindent();
if (wrapInParens)
{
OutputPossibleLineBreak(')');
if (node.FunctionType == FunctionType.ArrowFunction)
{
Output(')');
}
else
{
OutputPossibleLineBreak(')');
}
MarkSegment(node, null, node.ParameterDeclarations.Context);
}
}
else if (node.FunctionType == FunctionType.ArrowFunction)
{
// empty arrow function parameters need the empty parentheses
OutputPossibleLineBreak('(');
OutputPossibleLineBreak(')');
Output(')');
m_startOfStatement = false;
}

Expand Down