Skip to content

Commit

Permalink
Merge pull request #597 from mbbsemu/modules-config-basepath
Browse files Browse the repository at this point in the history
Modules Config "BasePath"
  • Loading branch information
paladine authored Nov 10, 2023
2 parents 1284426 + b1bb640 commit a63ce16
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 4 deletions.
10 changes: 10 additions & 0 deletions MBBSEmu.Tests/Assets/Module_Single_NoPatch_BasePath_Linux.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"BasePath" : "/dos/",
"Modules": [
{
"Identifier": "MBBSEMU",
"Path": "modules/mbbsemu/",
"Enabled": "true"
}
]
}
10 changes: 10 additions & 0 deletions MBBSEmu.Tests/Assets/Module_Single_NoPatch_BasePath_Windows.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"BasePath" : "c:\\dos\\",
"Modules": [
{
"Identifier": "MBBSEMU",
"Path": "modules\\mbbsemu\\",
"Enabled": "true"
}
]
}
105 changes: 105 additions & 0 deletions MBBSEmu.Tests/Converters/JsonModuleConfigurationFileConverter_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using MBBSEmu.Converters;
using MBBSEmu.Module;
using MBBSEmu.Resources;
using System;
using System.Text.Json;
using Xunit;

namespace MBBSEmu.Tests.Converters
{
public class JsonModuleConfigurationFileConverter_Tests : TestBase
{
[Fact]
public void Module_Single_NoPatch_BasePath()
{
var resourceManager = ResourceManager.GetTestResourceManager();
var jsonToDeserialize = string.Empty;
var expectedPath = "";

//Determine Platform and using a switch, set the file to be opened using resourceManager and the resulting BasePath
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32Windows:
case PlatformID.Win32S:
case PlatformID.WinCE:
case PlatformID.Win32NT:

jsonToDeserialize =
resourceManager.GetString("MBBSEmu.Tests.Assets.Module_Single_NoPatch_BasePath_Windows.json");
expectedPath = @"c:\dos\modules\mbbsemu\";
break;
case PlatformID.MacOSX:
case PlatformID.Unix:
jsonToDeserialize =
resourceManager.GetString("MBBSEmu.Tests.Assets.Module_Single_NoPatch_BasePath_Linux.json");
expectedPath = "/dos/modules/mbbsemu/";
break;
default:
throw new PlatformNotSupportedException();
}


var options = new JsonSerializerOptions
{
Converters =
{
new JsonModuleConfigurationFileConverter(),
new JsonBooleanConverter()
}
};

var result = JsonSerializer.Deserialize<ModuleConfigurationFile>(jsonToDeserialize, options);
Assert.NotNull(result);
Assert.Single(result.Modules);

var module = result.Modules[0];
Assert.Equal(expectedPath, module.ModulePath);
}

[Fact]
public void Module_Single_NoPatch_BasePath_NoConverter()
{
var resourceManager = ResourceManager.GetTestResourceManager();
var jsonToDeserialize = string.Empty;
var expectedPath = "";

//Determine Platform and using a switch, set the file to be opened using resourceManager and the resulting BasePath
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32Windows:
case PlatformID.Win32S:
case PlatformID.WinCE:
case PlatformID.Win32NT:

jsonToDeserialize =
resourceManager.GetString("MBBSEmu.Tests.Assets.Module_Single_NoPatch_BasePath_Windows.json");
expectedPath = @"modules\mbbsemu\";
break;
case PlatformID.MacOSX:
case PlatformID.Unix:
jsonToDeserialize =
resourceManager.GetString("MBBSEmu.Tests.Assets.Module_Single_NoPatch_BasePath_Linux.json");
expectedPath = "modules/mbbsemu/";
break;
default:
throw new PlatformNotSupportedException();
}

var options = new JsonSerializerOptions
{
Converters =
{
new JsonBooleanConverter()
}
};


var result = JsonSerializer.Deserialize<ModuleConfigurationFile>(jsonToDeserialize, options);
Assert.NotNull(result);
Assert.Single(result.Modules);

var module = result.Modules[0];
Assert.Equal(expectedPath, module.ModulePath);
}
}
}
4 changes: 4 additions & 0 deletions MBBSEmu.Tests/MBBSEmu.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<None Remove="Assets\Module_Multiple_NoPatch.json" />
<None Remove="Assets\Module_Multiple_Patch.json" />
<None Remove="Assets\Module_Single_NoPatch.json" />
<None Remove="Assets\Module_Single_NoPatch_BasePath_Linux.json" />
<None Remove="Assets\Module_Single_NoPatch_BasePath_Windows.json" />
<None Remove="Assets\Module_Single_Patch.json" />
</ItemGroup>

Expand Down Expand Up @@ -46,6 +48,8 @@
<EmbeddedResource Include="Assets\MBBSEMU.MSG" />
<EmbeddedResource Include="Assets\Module_Multiple_NoPatch.json" />
<EmbeddedResource Include="Assets\Module_Multiple_Patch.json" />
<EmbeddedResource Include="Assets\Module_Single_NoPatch_BasePath_Windows.json" />
<EmbeddedResource Include="Assets\Module_Single_NoPatch_BasePath_Linux.json" />
<EmbeddedResource Include="Assets\Module_Single_NoPatch.json" />
<EmbeddedResource Include="Assets\Module_Single_Patch.json" />
<EmbeddedResource Include="Assets\IntegrationTest.msg" />
Expand Down
79 changes: 79 additions & 0 deletions MBBSEmu/Converters/JsonModuleConfigurationConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using MBBSEmu.Module;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace MBBSEmu.Converters
{
/// <summary>
/// Custom JSON Converter used to load Module Configuration Files and propagate overriding values (Path, etc.) to
/// each Module defined in the configuration file.
/// </summary>
public class JsonModuleConfigurationFileConverter : JsonConverter<ModuleConfigurationFile>
{
public override ModuleConfigurationFile Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException("Expected a JSON object.");
}

var config = new ModuleConfigurationFile();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
// Ensure that the modules are initialized even if not present in the JSON.
config.Modules ??= new List<ModuleConfiguration>();
return config;
}

// Get the property name.
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException("Expected a property name.");
}

var propertyName = reader.GetString();
reader.Read(); // Move to the property value.

switch (propertyName)
{
case nameof(ModuleConfigurationFile.BasePath):
{
config.BasePath = JsonSerializer.Deserialize<string>(ref reader, options);

//Set to PWD if "." is specified
if (config.BasePath == ".")
config.BasePath = System.IO.Directory.GetCurrentDirectory();
}
break;
case nameof(ModuleConfigurationFile.Modules):
var modules = JsonSerializer.Deserialize<List<JsonElement>>(ref reader, options);
if (modules != null)
{
config.Modules = new List<ModuleConfiguration>(modules.Count);
foreach (var element in modules)
{
var moduleJson = element.GetRawText();
var module = JsonSerializer.Deserialize<ModuleConfiguration>(moduleJson, options);
module.BasePath = config.BasePath ?? "";
config.Modules.Add(module);
}
}
break;
default:
throw new JsonException($"Property '{propertyName}' is not supported.");
}
}

throw new JsonException("Expected a JSON object end.");
}

public override void Write(Utf8JsonWriter writer, ModuleConfigurationFile value, JsonSerializerOptions options)
{
throw new NotSupportedException("This converter does not support writing JSON.");
}
}
}
43 changes: 42 additions & 1 deletion MBBSEmu/Module/ModuleConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,34 @@ namespace MBBSEmu.Module

public class ModuleConfiguration
{
/// <summary>
/// Base Path for all Modules defined within the Module Configuration File
/// </summary>
public string BasePath;

/// <summary>
/// Backing Field for Module Path
/// </summary>
private string _modulePath;

/// <summary>
/// Default Constructor
/// </summary>
public ModuleConfiguration()
{
}

/// <summary>
/// Constructor with Base Path
/// </summary>
/// <param name="basePath">
/// Base Path for all Modules defined within the Module Configuration File
/// </param>
public ModuleConfiguration(string basePath)
{
BasePath = basePath;
}

/// <summary>
/// Module "Identifier" from moduleConfig.json or commandline
/// </summary>
Expand All @@ -17,9 +45,22 @@ public class ModuleConfiguration

/// <summary>
/// Module "Path" from moduleConfig.json or commandline
///
/// If Base Path is configured in the parent node, it will be prepended to this value
/// </summary>
[JsonPropertyName("Path")]
public string ModulePath { get; set; }
public string ModulePath
{
get
{
//If a base path specified and the module path is relative (both Linux and Windows), combine them
if (!string.IsNullOrWhiteSpace(BasePath) && !System.IO.Path.IsPathRooted(_modulePath))
return System.IO.Path.Combine(BasePath, _modulePath);

return _modulePath;
}
set => _modulePath = value;
}

/// <summary>
/// Module "MenuOptionKey" from moduleConfig.json or commandline
Expand Down
11 changes: 11 additions & 0 deletions MBBSEmu/Module/ModuleConfigurationFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@

namespace MBBSEmu.Module
{
/// <summary>
/// Class Representing a Deserialized Module Configuration File (JSON)
/// </summary>
public class ModuleConfigurationFile
{
/// <summary>
/// Base Path for all Modules defined within the Module Configuration File
/// </summary>
public string BasePath { get; set; }

/// <summary>
/// Array of Modules to be loaded by MBBSEmu
/// </summary>
public List<ModuleConfiguration> Modules { get; set; }
}
}
7 changes: 4 additions & 3 deletions MBBSEmu/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,10 @@ private void Run(string[] args)
var options = new JsonSerializerOptions
{
Converters = {
new JsonBooleanConverter(),
new JsonStringEnumConverter(),
new JsonFarPtrConverter()
new JsonModuleConfigurationFileConverter(), //Handles BasePath processing for Module Configuration
new JsonBooleanConverter(), //Allows TRUE/FALSE values to be parsed
new JsonStringEnumConverter(), //Allows Enums to be parsed from Strings
new JsonFarPtrConverter() //Allows FarPtr to be parsed from Strings
}
};

Expand Down

0 comments on commit a63ce16

Please sign in to comment.