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

refactoring #531

Merged
merged 12 commits into from
Jan 30, 2024
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
2 changes: 1 addition & 1 deletion src/PAModelTests/DataSourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using Microsoft.PowerPlatform.Formulas.Tools;
using Microsoft.PowerPlatform.Formulas.Tools.Extensions;
using Microsoft.PowerPlatform.Formulas.Tools.IO;
using Microsoft.PowerPlatform.PowerApps.Persistence.MsApp;
using Microsoft.PowerPlatform.PowerApps.Persistence;

namespace PAModelTests;

Expand Down
76 changes: 40 additions & 36 deletions src/Persistence.Tests/MsApp/MsappArchiveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
// Licensed under the MIT License.

using System.IO.Compression;
using Microsoft.PowerPlatform.PowerApps.Persistence.MsApp;
using Microsoft.PowerPlatform.PowerApps.Persistence.Yaml;
using Microsoft.PowerPlatform.PowerApps.Persistence;
using Microsoft.PowerPlatform.PowerApps.Persistence.Extensions;

namespace Persistence.Tests.MsApp;

[TestClass]
public class MsappArchiveTests
{
[DataRow(new string[] { "abc.txt" }, MsappArchive.ResourcesDirectory, 0)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\abc.txt" }, MsappArchive.ResourcesDirectory, 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\abc.txt" }, $@" \{MsappArchive.ResourcesDirectory}/", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}/abc.txt" }, $@" {MsappArchive.ResourcesDirectory}/", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}/abc.txt" }, $@" {MsappArchive.ResourcesDirectory}\", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\abc.txt" }, "NotFound", 0)]
[DataRow(new string[] { "abc.txt" }, MsappArchive.Directories.Resources, 0)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.Directories.Resources}\abc.txt" }, MsappArchive.Directories.Resources, 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.Directories.Resources}\abc.txt" }, $@" \{MsappArchive.Directories.Resources}/", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.Directories.Resources}/abc.txt" }, $@" {MsappArchive.Directories.Resources}/", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.Directories.Resources}/abc.txt" }, $@" {MsappArchive.Directories.Resources}\", 1)]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.Directories.Resources}\abc.txt" }, "NotFound", 0)]
[DataRow(new string[] {"abc.txt",
@$"{MsappArchive.ResourcesDirectory}\abc.txt",
@$"ReSoUrCeS/efg.txt"}, MsappArchive.ResourcesDirectory, 2)]
@$"{MsappArchive.Directories.Resources}\abc.txt",
@$"ReSoUrCeS/efg.txt"}, MsappArchive.Directories.Resources, 2)]
[DataRow(new string[] {"abc.txt",
@$"{MsappArchive.ResourcesDirectory}\abc.txt",
@$"{MsappArchive.ResourcesDirectory}/efg.txt"}, "RESOURCES", 2)]
@$"{MsappArchive.Directories.Resources}\abc.txt",
@$"{MsappArchive.Directories.Resources}/efg.txt"}, "RESOURCES", 2)]
[DataRow(new string[] {"abc.txt",
@$"{MsappArchive.ResourcesDirectory}New\abc.txt",
@$"{MsappArchive.ResourcesDirectory}/efg.txt"}, MsappArchive.ResourcesDirectory, 1)]
@$"{MsappArchive.Directories.Resources}New\abc.txt",
@$"{MsappArchive.Directories.Resources}/efg.txt"}, MsappArchive.Directories.Resources, 1)]
[TestMethod]
public void GetDirectoryEntriesTests(string[] entries, string directoryName, int expectedDirectoryCount)
{
Expand All @@ -45,12 +45,9 @@ public void GetDirectoryEntriesTests(string[] entries, string directoryName, int
msappArchive.GetDirectoryEntries(directoryName).Count().Should().Be(expectedDirectoryCount);
}

[DataRow(new string[] { "abc.txt" })]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\abc.txt" })]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\DEF.txt" })]
[DataRow(new string[] { "abc.txt", @$"{MsappArchive.ResourcesDirectory}\DEF.txt", @"\start-with-slash\test.json" })]
[TestMethod]
public void AddEntryTests(string[] entries)
[DataTestMethod]
[DynamicData(nameof(AddEntryTestsData), DynamicDataSourceType.Method)]
public void AddEntryTests(string[] entries, string[] expectedEntries)
{
// Arrange: Create new ZipArchive in memory
using var stream = new MemoryStream();
Expand All @@ -62,30 +59,37 @@ public void AddEntryTests(string[] entries)

// Assert
msappArchive.CanonicalEntries.Count.Should().Be(entries.Length);
foreach (var entry in entries)
for (var i = 0; i != expectedEntries.Length; ++i)
{
msappArchive.CanonicalEntries.ContainsKey(MsappArchive.NormalizePath(entry)).Should().BeTrue();
msappArchive.CanonicalEntries.ContainsKey(expectedEntries[i])
.Should()
.BeTrue($"Expected entry {expectedEntries[i]} to exist in the archive");
}

// Get the required entry should throw if it doesn't exist
var action = () => msappArchive.GetRequiredEntry("not-exist");
action.Invoking(a => a()).Should().Throw<FileNotFoundException>();
}

[TestMethod]
[DataRow(@"_TestData/AppsWithYaml/HelloWorld.msapp", 14, 2, "HelloScreen", "screen", 8)]
public void Msapp_ShouldHave_Screens(string testFile, int allEntriesCount, int controlsCount,
mizrael marked this conversation as resolved.
Show resolved Hide resolved
string topLevelControlName, string topLevelControlType,
int topLevelRulesCount)
private static IEnumerable<object[]> AddEntryTestsData()
{
// Arrange: Create new ZipArchive in memory
using var msappArchive = new MsappArchive(testFile, YamlSerializationFactory.CreateDeserializer());

// Assert
msappArchive.CanonicalEntries.Count.Should().Be(allEntriesCount);
msappArchive.Screens.Count.Should().Be(controlsCount);
msappArchive.Screens.Should().ContainSingle(c => c.Name == "App");

var screen = msappArchive.Screens.Single(c => c.Name == topLevelControlName);
return new[] {
new [] {
new[] { "abc.txt" },
new[] { "abc.txt" }
},
new[]{
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}\abc.txt" },
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}/abc.txt".ToLowerInvariant() },
},
new[]{
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}\DEF.txt" },
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}/DEF.txt".ToLowerInvariant() },
},
new[]{
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}\DEF.txt", @"\start-with-slash\test.json" },
new [] { "abc.txt", @$"{MsappArchive.Directories.Resources}/DEF.txt".ToLowerInvariant(), @"start-with-slash/test.json" },
}
};
}
}
5 changes: 4 additions & 1 deletion src/Persistence.Tests/Persistence.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<SignAssembly>false</SignAssembly>

<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
<PublicSign>true</PublicSign>
</PropertyGroup>

<ItemGroup>
Expand Down
5 changes: 2 additions & 3 deletions src/Persistence.Tests/Yaml/DeserializerInvalidTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.PowerPlatform.PowerApps.Persistence.MsApp;
using Microsoft.PowerPlatform.PowerApps.Persistence.Yaml;

namespace Persistence.Tests.Yaml;
Expand All @@ -10,12 +9,12 @@ namespace Persistence.Tests.Yaml;
public class DeserializerInvalidTests
{
[TestMethod]
public void Deserialize_ShouldFail()
public void Deserialize_ShouldFailWhenYamlIsInvalid()
{
// Arrange
var deserializer = YamlSerializationFactory.CreateDeserializer();

var files = Directory.GetFiles(@"_TestData/InvalidYaml", $"*{MsappArchive.YamlFxFileExtension}", SearchOption.AllDirectories);
var files = Directory.GetFiles(@"_TestData/InvalidYaml", $"*.fx.yaml", SearchOption.AllDirectories);
mizrael marked this conversation as resolved.
Show resolved Hide resolved
// Uncomment to test single file
// var files = new string[] { @"_TestData/InvalidYaml/InvalidName.fx.yaml" };

Expand Down
14 changes: 10 additions & 4 deletions src/Persistence/Attributes/FirstClassAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ namespace Microsoft.PowerPlatform.PowerApps.Persistence.Attributes;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
public class FirstClassAttribute : Attribute
{
public FirstClassAttribute(string? nodeName = null)
public FirstClassAttribute(string shortName, string templateUri)
{
NodeName = nodeName ?? string.Empty;
if (string.IsNullOrWhiteSpace(shortName))
throw new ArgumentException($"'{nameof(shortName)}' cannot be null or whitespace.", nameof(shortName));
if (string.IsNullOrWhiteSpace(templateUri))
throw new ArgumentException($"'{nameof(templateUri)}' cannot be null or whitespace.", nameof(templateUri));

ShortName = shortName;
TemplateUri = templateUri;
}

public string NodeName { get; }
public string ShortName { get; }

public required string TemplateUri { get; init; }
public string TemplateUri { get; }
}
26 changes: 26 additions & 0 deletions src/Persistence/Extensions/IMsappArchiveExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.IO.Compression;

namespace Microsoft.PowerPlatform.PowerApps.Persistence.Extensions;

public static class IMsappArchiveExtensions
{
/// <summary>
/// Returns the entry in the archive with the given name or throws a <see cref="FileNotFoundException"/> if it does not exist.
/// </summary>
/// <param name="archive">the <see cref="IMsappArchive"/> instance.</param>
/// <param name="entryName">the name of the entry to fetch.</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="FileNotFoundException"></exception>
public static ZipArchiveEntry GetRequiredEntry(this IMsappArchive archive, string entryName)
mizrael marked this conversation as resolved.
Show resolved Hide resolved
{
var entry = archive.GetEntry(entryName) ??
throw new FileNotFoundException($"Entry '{entryName}' not found in msapp archive.");

return entry;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using System.IO.Compression;

namespace Microsoft.PowerPlatform.PowerApps.Persistence.MsApp;
namespace Microsoft.PowerPlatform.PowerApps.Persistence;

/// <summary>
/// base interface for MsappArchive
Expand All @@ -26,6 +26,14 @@ public interface IMsappArchive
/// <returns>the entry or null when not found.</returns>
ZipArchiveEntry? GetEntry(string entryName);

/// <summary>
/// Returns all entries in the archive that are in the given directory.
/// </summary>
/// <param name="directoryName"></param>
/// <param name="extension"></param>
/// <returns></returns>
IEnumerable<ZipArchiveEntry> GetDirectoryEntries(string directoryName, string? extension = null);

/// <summary>
/// Provides access to the underlying zip archive.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Microsoft.PowerPlatform.PowerApps.Persistence.JsonConverters;
namespace Microsoft.PowerPlatform.PowerApps.Persistence.Json;

public class JsonDoubleToIntConverter : JsonConverter<int>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.PowerFx.Core" Version="1.2.0" />
<PackageReference Include="YamlDotNet" Version="$(YamlDotNetVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingVersion)" />
</ItemGroup>

<ItemGroup Condition="'$(GitExists)' == true">
Expand All @@ -48,6 +48,10 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Persistence.Tests" Key="0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
</ItemGroup>

<Target Name="SetAssemblyVersion" AfterTargets="MinVer">
<PropertyGroup>
<AssemblyVersion>$(MinVer)</AssemblyVersion>
Expand Down
4 changes: 2 additions & 2 deletions src/Persistence/Models/BuiltInTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ static BuiltInTemplates()

if (type.GetCustomAttributes(true).FirstOrDefault(a => a is FirstClassAttribute) is FirstClassAttribute firstClassAttribute)
{
shortNameToType.Add(firstClassAttribute.NodeName, type);
typeToShortName.Add(type, firstClassAttribute.NodeName);
shortNameToType.Add(firstClassAttribute.ShortName, type);
typeToShortName.Add(type, firstClassAttribute.ShortName);
templateToType.Add(firstClassAttribute.TemplateUri, type);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Persistence/Models/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.PowerPlatform.PowerApps.Persistence.Models;

[FirstClass(nameof(Button), TemplateUri = BuiltInTemplates.Button)]
[FirstClass(shortName: nameof(Button), templateUri: BuiltInTemplates.Button)]
public record Button : Control
{
public Button()
Expand Down
12 changes: 4 additions & 8 deletions src/Persistence/Models/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.PowerPlatform.PowerApps.Persistence.Collections;
using Microsoft.PowerPlatform.PowerApps.Persistence.Yaml;
using YamlDotNet.Serialization;

namespace Microsoft.PowerPlatform.PowerApps.Persistence.Models;

[DebuggerDisplay("{Name}")]
public abstract record Control
{
public const string YamlName = "Control";

public Control()
{
}
Expand All @@ -27,7 +26,7 @@ public Control(string name)
/// <summary>
/// template uri of the control.
/// </summary>
[YamlMember(Alias = YamlName, Order = 0)]
[YamlMember(Alias = YamlFields.Control, Order = 0)]
public required string ControlUri { get; init; }

private readonly string _name = string.Empty;
Expand Down Expand Up @@ -55,10 +54,7 @@ public required string Name

/// <summary>
/// list of child controls nested under this control.
/// </summary>
/// </summary>
[YamlMember(Order = 3)]
public IList<Control> Controls { get; init; } = new List<Control>();

[YamlIgnore]
public ControlEditorState? EditorState { get; set; }
mizrael marked this conversation as resolved.
Show resolved Hide resolved
public Control[] Controls { get; init; } = Array.Empty<Control>();
mizrael marked this conversation as resolved.
Show resolved Hide resolved
}
25 changes: 0 additions & 25 deletions src/Persistence/Models/ControlEditorState.cs

This file was deleted.

14 changes: 0 additions & 14 deletions src/Persistence/Models/ControlProperty.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/Persistence/Models/Screen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.PowerPlatform.PowerApps.Persistence.Models;

[FirstClass(nameof(Screen), TemplateUri = BuiltInTemplates.Screen)]
[FirstClass(shortName: nameof(Screen), templateUri: BuiltInTemplates.Screen)]
public record Screen : Control
{
public Screen()
Expand Down
2 changes: 1 addition & 1 deletion src/Persistence/Models/Text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.PowerPlatform.PowerApps.Persistence.Models;

[FirstClass(nameof(Text), TemplateUri = BuiltInTemplates.Text)]
[FirstClass(shortName: nameof(Text), templateUri: BuiltInTemplates.Text)]
public record Text : Control
{
public Text()
Expand Down
Loading
Loading