Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Serializing dictionary with ', ", . in key & #37 #38

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
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
13 changes: 13 additions & 0 deletions Tomlet.Tests/CommentSerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,17 @@ public void CommentAttributesWork()
Assert.Equal("The password you use to access the mailbox", doc.GetValue("password").Comments.InlineComment);
Assert.Equal("The rules for the mailbox follow", doc.GetArray("rules").Comments.PrecedingComment);
}

[Fact]
public void TrailingCommentWorks()
{
var document = TomlDocument.CreateEmpty();
document.TrailingComment = "Hello World!";
var output = document.SerializedValue;
Assert.Equal("\n# Hello World!", output);

document.Put("Hello", "World");
output = document.SerializedValue;
Assert.Equal("Hello = \"World\"\n\n# Hello World!", output);
}
}
324 changes: 250 additions & 74 deletions Tomlet.Tests/DeliberatelyIncorrectTestResources.Designer.cs

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions Tomlet.Tests/DeliberatelyIncorrectTestResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
<data name="TomlTruncatedFileExample" xml:space="preserve">
<value>string =</value>
</data>
<data name="TomlTruncatedFileExample2" xml:space="preserve">
<value>[</value>
</data>
<data name="TomlTruncatedFileExample3" xml:space="preserve">
<value>string</value>
</data>
<data name="TomlTableArrayWithMissingIntermediateExample" xml:space="preserve">
<value>[[numbers.one]]
value = 1</value>
Expand Down
62 changes: 43 additions & 19 deletions Tomlet.Tests/ExceptionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Tomlet.Exceptions;
using Tomlet.Models;
using Tomlet.Tests.TestModelClasses;
Expand Down Expand Up @@ -62,6 +63,14 @@ public void InvalidDatesThrow() =>
public void TruncatedFilesThrow() =>
AssertThrows<TomlEndOfFileException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlTruncatedFileExample));

[Fact]
public void TruncatedFilesThrow2() =>
AssertThrows<TomlEndOfFileException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlTruncatedFileExample2));

[Fact]
public void TruncatedFilesThrow3() =>
AssertThrows<TomlEndOfFileException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlTruncatedFileExample3));

[Fact]
public void UndefinedTableArraysThrow() =>
AssertThrows<MissingIntermediateInTomlTableArraySpecException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlTableArrayWithMissingIntermediateExample));
Expand All @@ -88,22 +97,15 @@ public void DatesWithUnnecessarySeparatorThrow() =>

[Fact]
public void ImplyingAValueIsATableViaDottedKeyInADocumentWhenItIsNotThrows() =>
AssertThrows<TomlDottedKeyParserException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlBadDottedKeyExample));

[Fact]
public void ImplyingAValueIsATableViaDottedKeyWhenItIsNotThrows()
{
var doc = GetDocument(TestResources.ArrayOfEmptyStringTestInput);
AssertThrows<TomlDottedKeyException>(() => doc.Put("Array.a", "foo"));
}
AssertThrows<TomlKeyRedefinitionException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlBadDottedKeyExample));

[Fact]
public void BadEnumValueThrows() =>
AssertThrows<TomlEnumParseException>(() => TomletMain.To<TomlTestClassWithEnum>(DeliberatelyIncorrectTestResources.TomlBadEnumExample));

[Fact]
public void ReDefiningASubTableAsASubTableArrayThrowsAnException() =>
AssertThrows<TomlKeyRedefinitionException>(() => GetDocument(DeliberatelyIncorrectTestResources.ReDefiningSubTableAsSubTableArrayTestInput));
AssertThrows<TomlTableRedefinitionException>(() => GetDocument(DeliberatelyIncorrectTestResources.ReDefiningSubTableAsSubTableArrayTestInput));

[Fact]
public void RedefiningAKeyAsATableNameThrowsAnException() =>
Expand Down Expand Up @@ -143,7 +145,7 @@ public void TripleQuotedKeysThrow() =>

[Fact]
public void WhitespaceInKeyThrows() =>
AssertThrows<TomlWhitespaceInKeyException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlWhitespaceInKeyExample));
AssertThrows<TomlMissingEqualsException>(() => GetDocument(DeliberatelyIncorrectTestResources.TomlWhitespaceInKeyExample));

[Fact]
public void MissingEqualsSignThrows() =>
Expand Down Expand Up @@ -211,20 +213,42 @@ public void GettingAValueWhichDoesntExistThrows() =>
public void MismatchingTypesInDeserializationThrow() =>
AssertThrows<TomlPropertyTypeMismatchException>(() => TomletMain.To<SimplePropertyTestClass>("MyFloat = \"hello\""));

[Fact]
public void AskingATableForTheValueAssociatedWithAnInvalidKeyThrows() =>
AssertThrows<InvalidTomlKeyException>(() => GetDocument("").GetBoolean("\"I am invalid'"));

[Fact]
public void SettingAnInlineCommentToIncludeANewlineThrows() =>
AssertThrows<TomlNewlineInInlineCommentException>(() => TomlDocument.CreateEmpty().Comments.InlineComment = "hello\nworld");

[Fact]
public void BadKeysThrow()
public void RedefiningDottedKeyThrows() => AssertThrows<TomlDottedKeyParserException>(
() =>
{
var parser = new TomlParser();
var tomlDocument = parser.Parse("""
a.b = 2
a.b.c = 3
""");
}
);

// These _can_ be converted, but since we're not we should add a proper exception for it
[Theory]
[InlineData("\x00")]
[InlineData("\x01")]
[InlineData("\x02")]
[InlineData("\x03")]
[InlineData("\x04")]
[InlineData("\x05")]
[InlineData("\x06")]
[InlineData("\x07")]
[InlineData("\x0b")]
[InlineData("\x0e")]
[InlineData("\x0f")]
public void SpecialCharactersCantBeKeys(string text)
{
var doc = GetDocument("");

//A key with both quotes
AssertThrows<InvalidTomlKeyException>(() => doc.GetLong("\"hello'"));
AssertThrows<InvalidTomlKeyException>(
() =>
{
var document = TomletMain.TomlStringFrom(new Dictionary<string, string> { { text, "a" } });
}
);
}
}
13 changes: 13 additions & 0 deletions Tomlet.Tests/ObjectToStringTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Tomlet.Models;
using Tomlet.Tests.TestModelClasses;
using Xunit;

Expand Down Expand Up @@ -111,5 +112,17 @@ public void AttemptingToDirectlySerializeNullThrows()
//We need to use a type of T that actually has something to serialize
Assert.Throws<ArgumentNullException>(() => TomletMain.DocumentFrom(typeof(SimplePrimitiveTestClass), null!, null));
}

[Fact]
public void DocumentToStringWorks()
{
var document = TomlDocument.CreateEmpty();
var output = document.ToString();
Assert.Equal("Toml root document (0 entries)", output);

document.Put("a", "a");
output = document.ToString();
Assert.Equal("Toml root document (1 entries)", output);
}
}
}
98 changes: 98 additions & 0 deletions Tomlet.Tests/QuotedKeyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Linq;
using Tomlet.Exceptions;
using Xunit;

namespace Tomlet.Tests
{
public class QuotedKeysTests
{
[Theory]
[InlineData("\"a.'b\"", "a.'b")] // a.'b
[InlineData("\"a.\\\"b\"", "a.\"b")] // a."b
[InlineData("\"\"", "")] //
[InlineData("\"\\\"\"", "\"")] // "
[InlineData("\"a.🐱b\"", "a.🐱b")] // a.🐱b
[InlineData("'a.\"b'", "a.\"b")] // a."b
[InlineData("'a.\\\"b'", "a.\\\"b")] // a.\"b
[InlineData("''", "")] //
[InlineData("'\"'", "\"")] // \"
[InlineData("'\\\"'", "\\\"")] // \"
[InlineData("'a.🐱b'", "a.🐱b")] // a.🐱b
[InlineData("\"a.b\\\".c\"", "a.b\".c")] // a.b".c
public void NonDottedKeysWork(string inputKey, string expectedKey)
{
var inputString = $"{inputKey} = \"value\"";
var dict = TomletMain.To<Dictionary<string, string>>(inputString);
Assert.Contains(expectedKey, (IDictionary<string, string>)dict);
}

[Theory]
[InlineData("\"a\"b\"")]
[InlineData("'a'b'")]
[InlineData("'a\\'b'")]
//[InlineData("a\"b")] // Illegal in specs, but no harm in reading it
//[InlineData("a'b")] // Illegal in specs, but no harm in reading it
//[InlineData("a🐱b")] // Illegal in specs, but no harm in reading it
[InlineData("'ab\"")]
public void IllegalNonDottedKeysThrow(string inputKey)
{
var inputString = $"{inputKey} = \"value\"";
Assert.ThrowsAny<TomlException>(() => _ = TomletMain.To<Dictionary<string, string>>(inputString));
}

[Theory]
[InlineData("'a.b'.c", "a.b", "c")]
[InlineData("'a.b'.\"c\"", "a.b", "c")]
[InlineData("a.'b.c'", "a", "b.c")]
[InlineData("\"a\".'b.c'", "a", "b.c")]
[InlineData("\"a\".b.c", "a", "b")]
[InlineData("'a.\"b'.c", "a.\"b", "c")]
[InlineData("\"a.b\\\"c\".d", "a.b\"c", "d")]
public void DottedKeysWork(string inputKey, string expectedKey, string expectedSubkey)
{
var inputString = $"{inputKey} = \"value\"";
var dict = TomletMain.To<Dictionary<string, Dictionary<string, string>>>(inputString);
var subDict = Assert.Contains(expectedKey, (IDictionary<string, Dictionary<string, string>>)dict);
Assert.Contains(expectedSubkey, (IDictionary<string, string>)subDict);
}

[Theory]
// [InlineData("'a.\"b'.c\"")] // Illegal in specs, but no harm in reading it
// [InlineData("\"a.bc\".d\"")] // Illegal in specs, but no harm in reading it
[InlineData("\"a.b\"c\".d\"")]
[InlineData("\"a.b\"c\".d")]
//[InlineData("\"a.b\\\"c\".d\"")] // Illegal in specs, but no harm in reading it
[InlineData("'a.b'c'.d")]
[InlineData("'a.b\\'c'.d")]
//[InlineData("'a.bc'.d'")] // Illegal in specs, but no harm in reading it
public void IllegalDottedKeysThrow(string inputKey)
{
var inputString = $"{inputKey} = \"value\"";
Assert.ThrowsAny<TomlException>(() => _ = TomletMain.To<Dictionary<string, string>>(inputString));
}


[Theory]
[InlineData("\"a\"b\"", @"^(?:'""a""b""')|(?:""\\""a\\""b\\"""")")] // Simple or Literal
[InlineData("'a'b'", @"^""'a'b'""")] // Simple only
[InlineData("'a\\'b'", @"^""'a\\\\'b'""")] // Simple only
[InlineData("a\"b", @"^(?:'a""b')|(?:""a\\""b"")")] // Simple or Literal
[InlineData("a'b", @"^""a'b""")] // Simple only
[InlineData("a🐱b", @"^(?:'a🐱b')|(?:""a🐱b"")")] // Simple or Literal
[InlineData("'ab\"", @"^""'ab\\""""")] // Simple only
public void SerializingIllegalKeysWorks(string inputKey, string expectedOutput)
{
var dict = new Dictionary<string, string>
{
{ inputKey, "z" },
};
var document = TomletMain.DocumentFrom(dict);
Assert.NotEmpty(document.Keys);
var parsedKey = document.Keys.First();
Assert.Equal(inputKey, parsedKey);
var serializedString = document.SerializedValue;
Assert.Matches(expectedOutput, serializedString);
}
}
}
Loading
Loading