Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [https://neo4j.com]
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using FluentAssertions;
using Neo4j.Driver.Mapping.ConventionTranslation;
using Xunit;

namespace Neo4j.Driver.Tests.Mapping.ConventionTranslation;

public class FormatterTests
{
[Fact]
public void SnakeCaseFormatter_ShouldFormat()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.SnakeCase);
var result = formatter.Format(new[] { "aPple", "BANANA", "Cherry" });
result.Should().Be("apple_banana_cherry");
}

[Fact]
public void SnakeCaseFormatter_ShouldCombineSingleToken()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.SnakeCase);
var result = formatter.Format(new[] { "aPple" });
result.Should().Be("apple");
}

[Fact]
public void CamelCaseFormatter_ShouldFormat()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.CamelCase);
var result = formatter.Format(new[] { "aPple", "BANANA", "Cherry" });
result.Should().Be("appleBananaCherry");
}

[Fact]
public void CamelCaseFormatter_ShouldCombineSingleToken()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.CamelCase);
var result = formatter.Format(new[] { "aPple" });
result.Should().Be("apple");
}

[Fact]
public void PascalCaseFormatter_ShouldFormat()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.PascalCase);
var result = formatter.Format(new[] { "aPple", "BANANA", "Cherry" });
result.Should().Be("AppleBananaCherry");
}

[Fact]
public void PascalCaseFormatter_ShouldCombineSingleToken()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.PascalCase);
var result = formatter.Format(new[] { "aPple" });
result.Should().Be("Apple");
}

[Fact]
public void ScreamingSnakeCaseFormatter_ShouldFormat()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.ScreamingSnakeCase);
var result = formatter.Format(new[] { "aPple", "BANANA", "Cherry" });
result.Should().Be("APPLE_BANANA_CHERRY");
}

[Fact]
public void ScreamingSnakeCaseFormatter_ShouldCombineSingleToken()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.ScreamingSnakeCase);
var result = formatter.Format(new[] { "aPple" });
result.Should().Be("APPLE");
}

[Fact]
public void KebabCaseFormatter_ShouldFormat()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.KebabCase);
var result = formatter.Format(new[] { "aPple", "BANANA", "Cherry" });
result.Should().Be("apple-banana-cherry");
}

[Fact]
public void KebabCaseFormatter_ShouldCombineSingleToken()
{
var formatter = new StandardCaseFormatter(FieldCaseConvention.KebabCase);
var result = formatter.Format(new[] { "aPple" });
result.Should().Be("apple");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [https://neo4j.com]
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using FluentAssertions;
using Neo4j.Driver.Mapping.ConventionTranslation;
using Xunit;

namespace Neo4j.Driver.Tests.Mapping.ConventionTranslation;

public class ParserTests
{
[Fact]
public void ShouldParseSnakeCaseTokens()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.SnakeCase);
var tokens = parser.ParseIdentifier("apple_banana_cherry");
tokens.Should().BeEquivalentTo("apple", "banana", "cherry");
}

[Fact]
public void ShouldParseCamelCaseTokens()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.CamelCase);
var tokens = parser.ParseIdentifier("appleBananaCherry");
tokens.Should().BeEquivalentTo("apple", "Banana", "Cherry");
}

[Fact]
public void ShouldParsePascalCaseTokens()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.PascalCase);
var tokens = parser.ParseIdentifier("AppleBananaCherry");
tokens.Should().BeEquivalentTo("Apple", "Banana", "Cherry");
}

[Fact]
public void ShouldParseScreamingSnakeCaseTokens()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.ScreamingSnakeCase);
var tokens = parser.ParseIdentifier("APPLE_BANANA_CHERRY");
tokens.Should().BeEquivalentTo("APPLE", "BANANA", "CHERRY");
}

[Fact]
public void ShouldParseKebabCaseTokens()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.KebabCase);
var tokens = parser.ParseIdentifier("apple-banana-cherry");
tokens.Should().BeEquivalentTo("apple", "banana", "cherry");
}

[Fact]
public void ShouldParseCSharpIdentifierTokens_LowerCaseStart()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.CSharpIdentifier);
var tokens = parser.ParseIdentifier("appleBananaCherry");
tokens.Should().BeEquivalentTo("apple", "Banana", "Cherry");
}

[Fact]
public void ShouldParseCSharpIdentifierTokens_UpperCaseStart()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.CSharpIdentifier);
var tokens = parser.ParseIdentifier("AppleBananaCherry");
tokens.Should().BeEquivalentTo("Apple", "Banana", "Cherry");
}

[Fact]
public void ShouldThrowExceptionForInvalidCamelCase()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.CamelCase);
Action act = () => parser.ParseIdentifier("AppleBananaCherry");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowExceptionForInvalidPascalCase()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.PascalCase);
Action act = () => parser.ParseIdentifier("appleBananaCherry");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowExceptionForInvalidSnakeCase()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.SnakeCase);
Action act = () => parser.ParseIdentifier("apple-Banana-Cherry");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowExceptionForInvalidScreamingSnakeCase()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.ScreamingSnakeCase);
Action act = () => parser.ParseIdentifier("APPLE-banana-CHERRY");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowExceptionForInvalidKebabCase()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.KebabCase);
Action act = () => parser.ParseIdentifier("apple_Banana_Cherry");
act.Should().Throw<ArgumentException>();
}

[Fact]
public void ShouldThrowExceptionForInvalidCSharpIdentifier()
{
var parser = new StandardCaseParser(IdentifierCaseConvention.CSharpIdentifier);
Action act = () => parser.ParseIdentifier("apple_bananaCherry");
act.Should().Throw<ArgumentException>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [https://neo4j.com]
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Collections.Generic;
using FluentAssertions;
using Neo4j.Driver.Internal.Types;
using Neo4j.Driver.Mapping;
using Neo4j.Driver.Mapping.ConventionTranslation;
using Neo4j.Driver.Tests.TestUtil;
using Xunit;

namespace Neo4j.Driver.Tests.Mapping.ConventionTranslation;

public class TranslationEndToEndTests : MappingTestWithGlobalState
{
[Fact]
public void ShouldDoDefaultTranslation()
{
var record = TestRecord.Create(["personName", "yearBorn"], ["Bob", 1977]);
RecordObjectMapping.TranslateIdentifiers();
var person = record.AsObjectFromBlueprint(new { PersonName = "", YearBorn = 0 });
person.PersonName.Should().Be("Bob");
person.YearBorn.Should().Be(1977);
}

[Fact]
public void ShouldMapKebabCaseFieldsToSnakeCaseProperties()
{
var record = TestRecord.Create(["person-name", "year-born"], ["Bob", 1977]);
RecordObjectMapping.TranslateIdentifiers(IdentifierCaseConvention.SnakeCase, FieldCaseConvention.KebabCase);
var person = record.AsObjectFromBlueprint(new { person_name = "", year_born = 0 });
person.person_name.Should().Be("Bob");
person.year_born.Should().Be(1977);
}

[Fact]
public void ShouldMapSnakeCaseFieldsToKebabCaseProperties()
{
var record = TestRecord.Create(["person_name", "year_born"], ["Bob", 1977]);
RecordObjectMapping.TranslateIdentifiers(
IdentifierCaseConvention.ScreamingSnakeCase,
FieldCaseConvention.SnakeCase);

var person = record.AsObjectFromBlueprint(new { PERSON_NAME = "", YEAR_BORN = 0 });
person.PERSON_NAME.Should().Be("Bob");
person.YEAR_BORN.Should().Be(1977);
}

private class ExplicitNamePerson
{
[MappingSource("name-of-person")]
public string Name { get; set; }

public int YearBorn { get; set; }
}

[Fact]
public void ShouldNotTranslateWhenPropertyIsMarkedWithMappingSourceAttribute()
{
var record = TestRecord.Create(["name-of-person", "year_born"], ["Bob", 1977]);
RecordObjectMapping.TranslateIdentifiers(FieldCaseConvention.SnakeCase);
var person = record.AsObject<ExplicitNamePerson>();
person.Name.Should().Be("Bob");
person.YearBorn.Should().Be(1977);
}

public record Person(int NumberOfMiddleNames, string FavouriteColor);

public class FlightCrew(Person pilot, Person coPilot)
{
public Person Pilot { get; set; }
public Person CoPilot { get; set; }
}

[Fact]
public void ShouldTranslateThroughNesting()
{
var pilotNode = new Node(
0,
[],
new Dictionary<string, object> { ["number_of_middle_names"] = 1, ["favourite_color"] = "red" });

var coPilotNode = new Node(
1,
[],
new Dictionary<string, object> { ["number_of_middle_names"] = 2, ["favourite_color"] = "blue" });

var record = TestRecord.Create(("pilot", pilotNode), ("co_pilot", coPilotNode));
RecordObjectMapping.TranslateIdentifiers(FieldCaseConvention.SnakeCase);

var flightCrew = record.AsObject<FlightCrew>();

flightCrew.Pilot.NumberOfMiddleNames.Should().Be(1);
flightCrew.Pilot.FavouriteColor.Should().Be("red");
flightCrew.CoPilot.NumberOfMiddleNames.Should().Be(2);
flightCrew.CoPilot.FavouriteColor.Should().Be("blue");
}
}
Loading