Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
standeren committed Dec 6, 2023
1 parent f5b45a1 commit 3571dcf
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 19 deletions.
10 changes: 8 additions & 2 deletions backend/src/DataModeling/Converter/Csharp/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ namespace Altinn.Studio.DataModeling.Converter.Csharp
{
public static class Compiler
{
/// <summary>
/// Try to compile csharp class from generated csharp code as string
/// </summary>
/// <param name="csharpCode">Csharp code as string</param>
/// <remarks>Throws a custom compiler exception with corresponding diagnostics if compilation fails</remarks>
/// <returns>The corresponding assembly</returns>
public static Assembly CompileToAssembly(string csharpCode)
{
var syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(csharpCode));
Expand All @@ -25,7 +31,7 @@ public static Assembly CompileToAssembly(string csharpCode)
.AddReferences(MetadataReference.CreateFromFile(typeof(Newtonsoft.Json.JsonPropertyAttribute).GetTypeInfo().Assembly.Location))
.AddSyntaxTrees(syntaxTree);

Assembly assembly = null;
Assembly assembly;
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
Expand All @@ -45,7 +51,7 @@ public static Assembly CompileToAssembly(string csharpCode)
customErrorMessages.Add(diagnostic.GetMessage());
}

throw new CsharpCompilationException($"// Compiler // CompileToAssembly // Csharp compilation failed with errors: {errors}", customErrorMessages);
throw new CsharpCompilationException("Csharp compilation failed.", customErrorMessages);
}
ms.Seek(0, SeekOrigin.Begin);
assembly = Assembly.Load(ms.ToArray());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Altinn.Studio.DataModeling.Converter.Interfaces;
using Altinn.Studio.DataModeling.Metamodel;
Expand All @@ -23,11 +21,6 @@ public JsonMetadataToCsharpConverter(CSharpGenerationSettings generationSettings

private string Indent(int level = 1) => new string(' ', level * _generationSettings.IndentSize);

public void TryGenerateCsharpClass(string csharpClass)
{
Compiler.CompileToAssembly(csharpClass);
}

/// <summary>
/// Create Model from ServiceMetadata object
/// </summary>
Expand All @@ -44,7 +37,6 @@ public string CreateModelFromMetadata(ModelMetadata serviceMetadata)
.AppendLine("using System.Collections.Generic;")
.AppendLine("using System.ComponentModel.DataAnnotations;")
.AppendLine("using System.Linq;")
.AppendLine("using System.Runtime;")
.AppendLine("using System.Text.Json.Serialization;")
.AppendLine("using System.Threading.Tasks;")
.AppendLine("using System.Xml.Serialization;")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,5 @@ public interface IModelMetadataToCsharpConverter
/// <param name="serviceMetadata">ServiceMetadata object</param>
/// <returns>The model code in C#</returns>
public string CreateModelFromMetadata(ModelMetadata serviceMetadata);

/// <summary>
/// Try to generate csharp class from generated string from metadata
/// </summary>
/// <param name="csharpClass">Csharp class as string</param>
/// <returns>Boolean indicator of successful generation</returns>
public void TryGenerateCsharpClass(string csharpClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ private Json.Schema.JsonSchema GenerateJsonSchemaFromXsd(Stream xsdStream)
private async Task UpdateCSharpClasses(AltinnAppGitRepository altinnAppGitRepository, ModelMetadata modelMetadata, string schemaName)
{
string csharpClasses = _modelMetadataToCsharpConverter.CreateModelFromMetadata(modelMetadata);
_modelMetadataToCsharpConverter.TryGenerateCsharpClass(csharpClasses);
Compiler.CompileToAssembly(csharpClasses);
await altinnAppGitRepository.SaveCSharpClasses(csharpClasses, schemaName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class PutDatamodelTests : DisagnerEndpointsTestsBase<PutDatamodelTests>,

private const string MinimumValidJsonSchema = "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"schema.json\",\"type\":\"object\",\"properties\":{\"rootType\":{\"$ref\":\"#/$defs/rootType\"}},\"$defs\":{\"rootType\":{\"properties\":{\"keyword\":{\"type\":\"string\"}}}}}";

private const string JsonSchemaThatWillNotCompile = "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$id\":\"schema.json\",\"type\":\"object\",\"properties\":{\"root\":{\"$ref\":\"#/$defs/rootType\"}},\"$defs\":{\"rootType\":{\"properties\":{\"keyword\":{\"type\":\"string\"}}}}}";

public PutDatamodelTests(WebApplicationFactory<Program> factory) : base(factory)
{
TargetTestRepository = TestDataHelper.GenerateTestRepoName();
Expand Down Expand Up @@ -64,6 +66,35 @@ public async Task ValidInput_ShouldReturn_NoContent_And_Create_Files(string mode
await FilesWithCorrectNameAndContentShouldBeCreated(modelName);
}

[Theory]
[InlineData("testModel.schema.json", "ttd", "hvem-er-hvem", "testUser")]
public async Task InvalidInput_ShouldReturn_BadRequest_And_CustomErrorMessages(string modelPath, string org, string repo, string user)
{
string url = $"{VersionPrefix(org, TargetTestRepository)}/datamodel?modelPath={modelPath}";

await CopyRepositoryForTest(org, repo, user, TargetTestRepository);

using var request = new HttpRequestMessage(HttpMethod.Put, url)
{
Content = new StringContent(JsonSchemaThatWillNotCompile, Encoding.UTF8, MediaTypeNames.Application.Json)
};

var response = await HttpClient.SendAsync(request);
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

var problemDetailsJson = await response.Content.ReadAsStringAsync();
var problemDetails = JsonSerializer.Deserialize<ProblemDetails>(problemDetailsJson);

problemDetails.Should().NotBeNull();
problemDetails.Extensions.Should().ContainKey("customErrorMessages");

var customErrorMessages = problemDetails.Extensions["customErrorMessages"];
customErrorMessages.Should().NotBeNull();
var customErrorMessagesElement = (JsonElement)customErrorMessages;
var firstErrorMessage = customErrorMessagesElement.EnumerateArray().FirstOrDefault().GetString();
firstErrorMessage.Should().Be("'root': member names cannot be the same as their enclosing type");
}

[Theory]
[InlineData("testModel.schema.json", "ttd", "hvem-er-hvem", "testUser", "Model/JsonSchema/General/NonXsdContextSchema.json")]
public async Task ValidSchema_ShouldReturn_NoContent_And_Create_Files(string modelPath, string org, string repo, string user, string schemaPath)
Expand Down
34 changes: 33 additions & 1 deletion backend/tests/Designer.Tests/Services/SchemaModelServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Xml.Schema;
using Altinn.Studio.DataModeling.Converter.Csharp;
using Altinn.Studio.DataModeling.Json.Keywords;
using Altinn.Studio.Designer.Factories;
using Altinn.Studio.Designer.Models;
Expand Down Expand Up @@ -110,7 +112,7 @@ public async Task UpdateSchema_AppRepo_ShouldUpdate()
// Act
ISchemaModelService schemaModelService = new SchemaModelService(altinnGitRepositoryFactory, TestDataHelper.LogFactory, TestDataHelper.ServiceRepositorySettings, TestDataHelper.XmlSchemaToJsonSchemaConverter, TestDataHelper.JsonSchemaToXmlSchemaConverter, TestDataHelper.ModelMetadataToCsharpConverter);
var expectedSchemaUpdates = @"{""properties"":{""rootType1"":{""$ref"":""#/definitions/rootType""}},""definitions"":{""rootType"":{""properties"":{""keyword"":{""type"":""string""}}}}}";
await schemaModelService.UpdateSchema(editingContext, $"App/models/HvemErHvem_SERES.schema.json", expectedSchemaUpdates);
await schemaModelService.UpdateSchema(editingContext, "App/models/HvemErHvem_SERES.schema.json", expectedSchemaUpdates);

// Assert
var altinnGitRepository = altinnGitRepositoryFactory.GetAltinnGitRepository(org, targetRepository, developer);
Expand Down Expand Up @@ -144,6 +146,36 @@ public async Task UpdateSchema_AppRepo_ShouldUpdate()
}
}

[Fact]
public async Task UpdateSchema_InvalidJsonSchema_ShouldThrowException()
{
// Arrange
var org = "ttd";
var sourceRepository = "hvem-er-hvem";
var developer = "testUser";
var targetRepository = TestDataHelper.GenerateTestRepoName();
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, targetRepository, developer);

await TestDataHelper.CopyRepositoryForTest(org, sourceRepository, developer, targetRepository);

var altinnGitRepositoryFactory = new AltinnGitRepositoryFactory(TestDataHelper.GetTestDataRepositoriesRootDirectory());

ISchemaModelService schemaModelService = new SchemaModelService(altinnGitRepositoryFactory,
TestDataHelper.LogFactory, TestDataHelper.ServiceRepositorySettings,
TestDataHelper.XmlSchemaToJsonSchemaConverter, TestDataHelper.JsonSchemaToXmlSchemaConverter,
TestDataHelper.ModelMetadataToCsharpConverter);
var invalidSchema =
@"{""properties"":{""root"":{""$ref"":""#/definitions/rootType""}},""definitions"":{""rootType"":{""properties"":{""keyword"":{""type"":""string""}}}}}";

var exception = await Assert.ThrowsAsync<CsharpCompilationException>(async () =>
{
await schemaModelService.UpdateSchema(editingContext, "App/models/HvemErHvem_SERES.schema.json", invalidSchema);
});

Assert.NotNull(exception.CustomErrorMessages);
Assert.Equal(new List<string>() { "'root': member names cannot be the same as their enclosing type" }, exception.CustomErrorMessages);
}

[Theory]
[InlineData("ttd", "apprepo", "test", "", "http://studio.localhost/repos")]
[InlineData("ttd", "apprepo", "test", "/path/to/folder/", "http://studio.localhost/repos")]
Expand Down

0 comments on commit 3571dcf

Please sign in to comment.