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
2 changes: 1 addition & 1 deletion ColorCode.Core/Compilation/Languages/Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ColorCode.Compilation.Languages
/// </summary>
public class Json : ILanguage
{
private const string Regex_String = @"""[^""\\]*(?:\\[^\r\n]|[^""\\]*)*""";
private const string Regex_String = @"""[^""\\]*(?:\\.[^""\\]*)*""";
private const string Regex_Number = @"-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][-+]?[0-9]+)?";

public string Id
Expand Down
23 changes: 23 additions & 0 deletions ColorCode.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ColorCode.UWP", "ColorCode.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorCode.UWPTests", "Tests\ColorCode.UWPTests\ColorCode.UWPTests.csproj", "{A3D5A8A5-1D1F-412D-A829-C3DC1C7D4DF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorCode.Core.UnitTests", "Tests\ColorCode.Core.UnitTests\ColorCode.Core.UnitTests.csproj", "{277FBC4B-50A4-440A-811F-39AEEB088978}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -201,6 +203,26 @@ Global
{A3D5A8A5-1D1F-412D-A829-C3DC1C7D4DF3}.Release|x86.ActiveCfg = Release|x86
{A3D5A8A5-1D1F-412D-A829-C3DC1C7D4DF3}.Release|x86.Build.0 = Release|x86
{A3D5A8A5-1D1F-412D-A829-C3DC1C7D4DF3}.Release|x86.Deploy.0 = Release|x86
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|Any CPU.Build.0 = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|ARM.ActiveCfg = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|ARM.Build.0 = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|ARM64.Build.0 = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|x64.ActiveCfg = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|x64.Build.0 = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|x86.ActiveCfg = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Debug|x86.Build.0 = Debug|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|Any CPU.ActiveCfg = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|Any CPU.Build.0 = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|ARM.ActiveCfg = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|ARM.Build.0 = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|ARM64.ActiveCfg = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|ARM64.Build.0 = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|x64.ActiveCfg = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|x64.Build.0 = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|x86.ActiveCfg = Release|Any CPU
{277FBC4B-50A4-440A-811F-39AEEB088978}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -210,6 +232,7 @@ Global
{F1ED6BD6-2690-4BF3-835C-C3927C33424F} = {5B9F207C-2EAB-4F77-95C7-206D65C87137}
{DD20D31A-915E-43A2-B819-3A7AE39CA25C} = {5B9F207C-2EAB-4F77-95C7-206D65C87137}
{A3D5A8A5-1D1F-412D-A829-C3DC1C7D4DF3} = {5B9F207C-2EAB-4F77-95C7-206D65C87137}
{277FBC4B-50A4-440A-811F-39AEEB088978} = {5B9F207C-2EAB-4F77-95C7-206D65C87137}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5A764590-3191-47F4-9257-5D5F63BC5713}
Expand Down
19 changes: 19 additions & 0 deletions Tests/ColorCode.Core.UnitTests/ColorCode.Core.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\ColorCode.HTML\ColorCode.HTML.csproj" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions Tests/ColorCode.Core.UnitTests/JsonBacktrackingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Threading.Tasks;
using Xunit;

namespace ColorCode.Core.UnitTests
{
/// <summary>
/// Regression tests for the JSON language's <c>Regex_String</c> catastrophic backtracking
/// (issue #45): malformed JSON must not send the highlighter into exponential-time matching.
/// </summary>
public class JsonBacktrackingTests
{
[Fact]
public void Partial_json_does_not_catastrophically_backtrack()
{
// A JSON array whose last string value is unterminated. With the old Regex_String the
// key rule explores O(2^n) ways to partition the string body and never returns; with
// the fix it is linear. Bound the call so the pre-fix state fails fast (this test
// running long IS the bug) instead of hanging the whole run.
var partial = "[\n { \"field\": \"" + new string('a', 40) + "\n";

string html = null;
var task = Task.Run(() => html = new HtmlClassFormatter().GetHtmlString(partial, Languages.FindById("json")));

Assert.True(
task.Wait(TimeSpan.FromSeconds(10)),
"Highlighting partial JSON did not finish in 10s — Regex_String is backtracking catastrophically (issue #45).");
Assert.NotNull(html);
}

[Fact]
public void Valid_json_still_highlights_keys_strings_and_escapes()
{
// The fix must not change how valid JSON is tokenised: keys, string values, and strings
// containing escaped quotes/backslashes all still colour correctly.
var json = "{ \"name\": \"John Doe\", \"path\": \"C:\\\\a\\\"b\" }";

var html = new HtmlClassFormatter().GetHtmlString(json, Languages.FindById("json"));

Assert.Contains("jsonKey", html);
Assert.Contains("jsonString", html);
Assert.Contains("John Doe", html);
}
}
}
Loading