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 Config serialization and empty Config serialization. #214

Merged
merged 2 commits into from
Jan 31, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/Hocon.Configuration.Test/SerializationSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static IEnumerable<object[]> HoconGenerator()
};
}

[Theory(Skip = "Doesn't work right now")]
[Theory]
[MemberData(nameof(HoconGenerator))]
public void ShouldSerializeHocon(string hocon, string fallback1, string fallback2)
{
Expand All @@ -42,8 +42,25 @@ public void ShouldSerializeHocon(string hocon, string fallback1, string fallback
private void VerifySerialization(Config config)
{
var serialized = JsonConvert.SerializeObject(config);
var deserialized = (Config)JsonConvert.DeserializeObject(serialized);
var deserialized = JsonConvert.DeserializeObject<Config>(serialized);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL - was this really as simple as just using the generic method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup... its just as simple as that

config.DumpConfig().Should().Be(deserialized.DumpConfig());
}

[Fact]
public void CanSerializeEmptyConfig()
{
var config = Config.Empty;
var serialized = JsonConvert.SerializeObject(config);
var deserialized = JsonConvert.DeserializeObject<Config>(serialized);
deserialized.IsEmpty.Should().BeTrue();
}

[Fact]
public void ShouldResolveEmptyToEmpty()
{
ConfigurationFactory.Empty.IsEmpty.Should().BeTrue();
ConfigurationFactory.ParseString("{}").IsEmpty.Should().BeTrue();
Config.Empty.IsEmpty.Should().BeTrue();
}
}
}
62 changes: 33 additions & 29 deletions src/Hocon.Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,32 @@ namespace Hocon
[Serializable]
public class Config : HoconRoot, ISerializable
{
/// <summary>
/// INTERNAL API
///
/// Special case for empty configurations. Immutable and can't be added as a fallback.
/// </summary>
internal sealed class EmptyConfig : Config
{
public static EmptyConfig Instance = new EmptyConfig();

private EmptyConfig() : base(new HoconRoot(new HoconEmptyValue(null)))
{
}

protected override Config Copy(Config fallback = null)
{
return Instance;
}

public override Config WithFallback(Config fallback)
{
return fallback;
}
}
private static readonly HoconValue _emptyValue;

public const string SerializedPropertyName = "_dump";

static Config()
{
_emptyValue = new HoconValue(null);
_emptyValue.Add(new HoconObject(_emptyValue));
}

[Obsolete("For json serialization/deserialization only", true)]
private Config()
{
}

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="Config" /> class.
/// </summary>
private Config(HoconValue value)
{
Value = value;
Root = GetRootValue();
}

/// <inheritdoc cref="Config(HoconValue)" />
private Config(HoconValue value, Config fallback)
{
Fallback = fallback;
Expand All @@ -63,15 +54,16 @@ private Config(HoconValue value, Config fallback)
Root = GetRootValue();
}

/// <inheritdoc cref="Config(HoconValue, Config)" />

/// <inheritdoc cref="Config(HoconValue)" />
/// <param name="root">The root node to base this configuration.</param>
/// <exception cref="T:System.ArgumentNullException">"The root value cannot be null."</exception>
public Config(HoconRoot root) : base(root?.Value, root?.Substitutions ?? Enumerable.Empty<HoconSubstitution>())
{
Root = GetRootValue();
}

/// <inheritdoc cref="Config(HoconValue, Config)" />
/// <inheritdoc cref="Config(HoconValue)" />
/// <param name="source">The configuration to use as the primary source.</param>
/// <param name="fallback">The configuration to use as a secondary source.</param>
/// <exception cref="ArgumentNullException">The source configuration cannot be null.</exception>
Expand All @@ -89,7 +81,7 @@ public Config(HoconRoot root) : base(root?.Value, root?.Substitutions ?? Enumera
/// <remarks>
/// Added for brevity and API backwards-compatibility with Akka.Hocon.
/// </remarks>
public static Config Empty => ConfigurationFactory.Empty;
public static Config Empty => CreateEmpty();
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The configuration used as a secondary source.
Expand All @@ -101,6 +93,11 @@ public Config(HoconRoot root) : base(root?.Value, root?.Substitutions ?? Enumera
/// </summary>
public virtual HoconValue Root { get; }

/// <summary>
/// Determines if this root node contains any values
/// </summary>
public virtual bool IsEmpty => Value == _emptyValue;

/// <summary>
/// Returns string representation of <see cref="Config" />, allowing to include fallback values
/// </summary>
Expand Down Expand Up @@ -166,7 +163,7 @@ public virtual Config WithFallback(Config fallback)
if (fallback == this)
throw new ArgumentException("Config can not have itself as fallback", nameof(fallback));

if (fallback == Config.Empty)
if (fallback.IsEmpty)
return this; // no-op

// If Fallback is not set - we will set it in new copy
Expand Down Expand Up @@ -219,7 +216,14 @@ public virtual Config WithFallback(Config fallback)
used.Add(kvp.Key);
}
}


private static Config CreateEmpty()
{
var value = new HoconValue(null);
value.Add(new HoconObject(value));
return new Config(value);
}

/// <summary>
/// Performs aggregation of Value and all Fallbacks into single <see cref="HoconValue"/> object
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Hocon.Configuration/ConfigurationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static class ConfigurationFactory
/// <summary>
/// Generates an empty configuration.
/// </summary>
public static Config Empty => Config.EmptyConfig.Instance;
public static Config Empty => Config.Empty;

/// <summary>
/// Generates a configuration defined in the supplied
Expand Down
5 changes: 0 additions & 5 deletions src/Hocon/HoconRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ public HoconRoot(HoconValue value, IEnumerable<HoconSubstitution> substitutions)
/// </summary>
public IEnumerable<HoconSubstitution> Substitutions { get; }

/// <summary>
/// Determines if this root node contains any values
/// </summary>
public virtual bool IsEmpty => Value == null || Value.Type == HoconType.Empty;

protected virtual HoconValue GetNode(HoconPath path, bool throwIfNotFound = false)
{
if (Value.Type != HoconType.Object)
Expand Down