Skip to content

Commit

Permalink
fix: makes reference of holder immutable
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
  • Loading branch information
baywet committed Feb 4, 2025
1 parent 92877e0 commit a182f44
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ public interface IOpenApiReferenceHolder : IOpenApiSerializable
/// <summary>
/// Reference object.
/// </summary>
OpenApiReference Reference { get; set; }
OpenApiReference Reference { get; init; }
}
}
14 changes: 13 additions & 1 deletion src/Microsoft.OpenApi/Models/OpenApiReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ public class OpenApiReference : IOpenApiSerializable, IOpenApiDescribedElement,
/// </summary>
public bool IsFragment { get; init; }

private OpenApiDocument openApiDocument;
/// <summary>
/// The OpenApiDocument that is hosting the OpenApiReference instance. This is used to enable dereferencing the reference.
/// </summary>
public OpenApiDocument HostDocument { get; init; }
public OpenApiDocument HostDocument { get => openApiDocument; init => openApiDocument = value; }

/// <summary>
/// Gets the full reference string for v3.0.
Expand Down Expand Up @@ -291,5 +292,16 @@ private string GetReferenceTypeNameAsV2(ReferenceType type)
// to indicate that the reference is not pointing to any object.
};
}

/// <summary>
/// Sets the host document after deserialization or before serialization.
/// This method is internal on purpose to avoid consumers mutating the host document.
/// </summary>
/// <param name="currentDocument">Host document to set if none is present</param>
internal void EnsureHostDocumentIsSet(OpenApiDocument currentDocument)
{
Utils.CheckArgumentNull(currentDocument);
openApiDocument ??= currentDocument;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected BaseOpenApiReferenceHolder(string referenceId, OpenApiDocument hostDoc
/// <inheritdoc/>
public bool UnresolvedReference { get => Reference is null || Target is null; }
/// <inheritdoc/>
public OpenApiReference Reference { get; set; }
public OpenApiReference Reference { get; init; }
/// <inheritdoc/>
public abstract V CopyReferenceAsTargetElementWithOverrides(V source);
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@ public ReferenceHostDocumentSetter(OpenApiDocument currentDocument)
/// <inheritdoc/>
public override void Visit(IOpenApiReferenceHolder referenceHolder)
{
if (referenceHolder.Reference != null)
{
referenceHolder.Reference = new OpenApiReference(referenceHolder.Reference)
{
HostDocument = _currentDocument,
};
}
referenceHolder.Reference?.EnsureHostDocumentIsSet(_currentDocument);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,7 @@ public async Task LoadResponseAndSchemaReference()
}
};

var schemaReference = (OpenApiSchemaReference)expected.Content["application/json"].Schema;
schemaReference.Reference = new OpenApiReference(schemaReference.Reference)
{
HostDocument = result.Document,
};
((OpenApiSchemaReference)expected.Content["application/json"].Schema).Reference.EnsureHostDocumentIsSet(result.Document);
var actual = reference.Target;

// Assert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1046,11 +1046,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed()
}
};

tagReference1.Reference = new OpenApiReference(tagReference1.Reference) {HostDocument = expected };
tagReference2.Reference = new OpenApiReference(tagReference2.Reference) {HostDocument = expected };
petSchemaReference.Reference = new OpenApiReference(petSchemaReference.Reference) {HostDocument = expected };
newPetSchemaReference.Reference = new OpenApiReference(newPetSchemaReference.Reference) {HostDocument = expected };
errorModelSchemaReference.Reference = new OpenApiReference(errorModelSchemaReference.Reference) {HostDocument = expected };
tagReference1.Reference.EnsureHostDocumentIsSet(expected);
tagReference2.Reference.EnsureHostDocumentIsSet(expected);
petSchemaReference.Reference.EnsureHostDocumentIsSet(expected);
newPetSchemaReference.Reference.EnsureHostDocumentIsSet(expected);
errorModelSchemaReference.Reference.EnsureHostDocumentIsSet(expected);

actual.Document.Should().BeEquivalentTo(expected, options => options
.IgnoringCyclicReferences()
Expand Down Expand Up @@ -1284,7 +1284,7 @@ public async Task ParseDocWithRefsUsingProxyReferencesSucceeds()
var outputDoc = (await doc.SerializeAsYamlAsync(OpenApiSpecVersion.OpenApi3_0)).MakeLineBreaksEnvironmentNeutral();
var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters[0];
var expectedParamReference = Assert.IsType<OpenApiParameterReference>(expectedParam);
expectedParamReference.Reference = new OpenApiReference(expectedParamReference.Reference) {HostDocument = doc};
expectedParamReference.Reference.EnsureHostDocumentIsSet(doc);

var actualParamReference = Assert.IsType<OpenApiParameterReference>(actualParam);

Expand Down
4 changes: 2 additions & 2 deletions test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ namespace Microsoft.OpenApi.Interfaces
}
public interface IOpenApiReferenceHolder : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
{
Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; }
bool UnresolvedReference { get; }
Microsoft.OpenApi.Models.OpenApiReference Reference { get; init; }
}
public interface IOpenApiReferenceHolder<out T, V> : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceHolder, Microsoft.OpenApi.Interfaces.IOpenApiSerializable
where out T : Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, V
Expand Down Expand Up @@ -1243,9 +1243,9 @@ namespace Microsoft.OpenApi.Models.References
protected readonly T _target;
protected BaseOpenApiReferenceHolder(Microsoft.OpenApi.Models.References.BaseOpenApiReferenceHolder<T, V> source) { }
protected BaseOpenApiReferenceHolder(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, Microsoft.OpenApi.Models.ReferenceType referenceType, string externalResource = null) { }
public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; }
public virtual T Target { get; }
public bool UnresolvedReference { get; }
public Microsoft.OpenApi.Models.OpenApiReference Reference { get; init; }
public abstract V CopyReferenceAsTargetElementWithOverrides(V source);
public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
Expand Down

0 comments on commit a182f44

Please # to comment.