diff --git a/src/Hl7.Fhir.Base/ElementModel/SourceNodeExtensions.cs b/src/Hl7.Fhir.Base/ElementModel/SourceNodeExtensions.cs index ac98b4c8c1..dc941d5272 100644 --- a/src/Hl7.Fhir.Base/ElementModel/SourceNodeExtensions.cs +++ b/src/Hl7.Fhir.Base/ElementModel/SourceNodeExtensions.cs @@ -170,6 +170,14 @@ public static string GetResourceTypeIndicator(this ISourceNode node) => /// public static IEnumerable Annotations(this ISourceNode node, Type type) => node is IAnnotated ann ? ann.Annotations(type) : Enumerable.Empty(); + + /// + /// Gets specific annotations from the list of annotations on the node. + /// + /// All of the annotations of the given type, or an empty list if none were found. + /// + public static IEnumerable Annotations(this ISourceNode node) => + (node is IAnnotated ann ? ann.Annotations() : []); /// /// Gets a specific annotation from the list of annotations on the node. diff --git a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs index 905d45d0bb..ede8590a8d 100644 --- a/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs +++ b/src/Hl7.Fhir.Base/ElementModel/TypedElementOnSourceNode.cs @@ -14,6 +14,8 @@ using System.Threading; using P = Hl7.Fhir.ElementModel.Types; +#nullable enable + namespace Hl7.Fhir.ElementModel { internal class TypedElementOnSourceNode : ITypedElement, IAnnotated, IExceptionSource, IShortPathGenerator @@ -21,7 +23,7 @@ internal class TypedElementOnSourceNode : ITypedElement, IAnnotated, IExceptionS private const string XHTML_INSTANCETYPE = "xhtml"; private const string XHTML_DIV_TAG_NAME = "div"; - public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefinitionSummaryProvider provider, TypedElementSettings settings = null) + public TypedElementOnSourceNode(ISourceNode source, string? type, IStructureDefinitionSummaryProvider provider, TypedElementSettings? settings = null) { if (source == null) throw Error.ArgumentNull(nameof(source)); @@ -31,12 +33,13 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin if (source is IExceptionSource ies && ies.ExceptionHandler == null) ies.ExceptionHandler = (o, a) => ExceptionHandler.NotifyOrThrow(o, a); + Location = source.Name; ShortPath = source.Name; _source = source; (InstanceType, Definition) = buildRootPosition(type); } - private (string instanceType, IElementDefinitionSummary definition) buildRootPosition(string type) + private (string instanceType, IElementDefinitionSummary? definition) buildRootPosition(string? type) { var rootType = type ?? _source.GetResourceTypeIndicator(); if (rootType == null) @@ -45,7 +48,7 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin throw Error.Format(nameof(type), $"Cannot determine the type of the root element at '{_source.Location}', " + $"please supply a type argument."); else - return (rootType, null); + return ("Base", null); } var elementType = Provider.Provide(rootType); @@ -66,7 +69,7 @@ public TypedElementOnSourceNode(ISourceNode source, string type, IStructureDefin } - private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode source, IElementDefinitionSummary definition, string instanceType, string prettyPath) + private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode source, IElementDefinitionSummary? definition, string instanceType, string prettyPath, string location) { _source = source; ShortPath = prettyPath; @@ -75,11 +78,12 @@ private TypedElementOnSourceNode(TypedElementOnSourceNode parent, ISourceNode so Definition = definition; InstanceType = instanceType; _settings = parent._settings; + Location = location; } - public ExceptionNotificationHandler ExceptionHandler { get; set; } + public ExceptionNotificationHandler? ExceptionHandler { get; set; } - private void raiseTypeError(string message, object source, bool warning = false, string location = null) + private void raiseTypeError(string message, object source, bool warning = false, string? location = null) { var exMessage = $"Type checking the data: {message}"; if (!string.IsNullOrEmpty(location)) @@ -101,7 +105,7 @@ private void raiseTypeError(string message, object source, bool warning = false, private readonly TypedElementSettings _settings; - public IElementDefinitionSummary Definition { get; private set; } + public IElementDefinitionSummary? Definition { get; private set; } public string Name => Definition?.ElementName ?? _source.Name; @@ -120,7 +124,7 @@ private void raiseTypeError(string message, object source, bool warning = false, // R3 and R4, these value (and url and id elements by the way) will indicate which type // of system types there are, implicitly specifying the mapping between primitive // FHIR types and system types. - private static Type tryMapFhirPrimitiveTypeToSystemType(string fhirType) + private static Type? tryMapFhirPrimitiveTypeToSystemType(string fhirType) { switch (fhirType) { @@ -158,7 +162,7 @@ private static Type tryMapFhirPrimitiveTypeToSystemType(string fhirType) } } - private object valueFactory() + private object? valueFactory() { string sourceText = _source.Text; @@ -209,7 +213,7 @@ private object valueFactory() if (P.Any.TryParse(sourceText, typeof(P.DateTime), out var dateTimeVal)) { // TruncateToDate converts 1991-02-03T11:22:33Z to 1991-02-03+00:00 which is not a valid date! - var date = (dateTimeVal as P.DateTime).TruncateToDate(); + var date = (dateTimeVal as P.DateTime)!.TruncateToDate(); // so we cut off timezone by converting it to timeoffset and cast back to date. return P.Date.FromDateTimeOffset(date.ToDateTimeOffset(0, 0, 0, TimeSpan.Zero)); } @@ -220,13 +224,13 @@ private object valueFactory() } } - private object _value; + private object? _value; private bool _valueInitialized = false; private static object _initializationLock = new(); - public object Value => LazyInitializer.EnsureInitialized(ref _value, ref _valueInitialized, ref _initializationLock, valueFactory); + public object Value => LazyInitializer.EnsureInitialized(ref _value, ref _valueInitialized, ref _initializationLock, valueFactory)!; - private string deriveInstanceType(ISourceNode current, IElementDefinitionSummary info) + private string? deriveInstanceType(ISourceNode current, IElementDefinitionSummary info) { var resourceTypeIndicator = current.GetResourceTypeIndicator(); @@ -338,7 +342,7 @@ private string typeFromLogicalModelCanonical(ITypeSerializationInfo info) return pos > -1 ? type.Substring(pos + 1) : type; } - private bool tryGetBySuffixedName(Dictionary dis, string name, out IElementDefinitionSummary info) + private bool tryGetBySuffixedName(Dictionary dis, string name, out IElementDefinitionSummary? info) { // Simplest case, one on one match between name and element name if (dis.TryGetValue(name, out info)) @@ -361,7 +365,7 @@ private bool tryGetBySuffixedName(Dictionary } } - private IEnumerable enumerateElements(Dictionary dis, ISourceNode parent, string name) + private IEnumerable enumerateElements(Dictionary dis, ISourceNode parent, string? name) { IEnumerable childSet; @@ -372,17 +376,17 @@ private IEnumerable enumerateElements(Dictionary(); } - string lastName = null; + string? lastName = null; int _nameIndex = 0; foreach (var scan in childSet) { var hit = tryGetBySuffixedName(dis, scan.Name, out var info); - string instanceType = info == null ? null : + string? instanceType = info == null ? null : deriveInstanceType(scan, info); // If we have definitions for the children, but we didn't find definitions for this @@ -406,28 +410,31 @@ private IEnumerable enumerateElements(Dictionary c.Annotation()?.XHtmlText); #pragma warning restore CS0618 // Type or member is obsolete var source = SourceNode.Valued(scan.Name, string.Join(string.Empty, xmls)); - yield return new TypedElementOnSourceNode(this, source, info, instanceType, prettyPath); + yield return new TypedElementOnSourceNode(this, source, info, instanceType, prettyPath, location); continue; } - yield return new TypedElementOnSourceNode(this, scan, info, instanceType, prettyPath); + yield return new TypedElementOnSourceNode(this, scan, info, instanceType!, prettyPath, location); } } - public IEnumerable Children(string name = null) + public IEnumerable Children(string? name = null) { // If we have an xhtml typed node and there is not a div tag around the content // then we will not enumerate through the children of this node, since there will be no types @@ -461,13 +468,13 @@ public IEnumerable Children(string name = null) private IEnumerable runAdditionalRules(IEnumerable children) { #pragma warning disable 612, 618 - var additionalRules = _source.Annotations(typeof(AdditionalStructuralRule)); + var additionalRules = _source.Annotations().ToArray(); var stateBag = new Dictionary(); foreach (var child in children) { - foreach (var rule in additionalRules.Cast()) + foreach (var rule in additionalRules) { - stateBag.TryGetValue(rule, out object state); + stateBag.TryGetValue(rule, out object? state); state = rule(child, this, state); if (state != null) stateBag[rule] = state; } @@ -477,18 +484,16 @@ private IEnumerable runAdditionalRules(IEnumerable #pragma warning restore 612, 618 } - public string Location => _source.Location; + public string Location { get; init; } public string ShortPath { get; private set; } public override string ToString() => - $"{(InstanceType != null ? ($"[{InstanceType}] ") : "")}{_source}"; + $"{(($"[{InstanceType}] "))}{_source}"; public IEnumerable Annotations(Type type) { -#pragma warning disable IDE0046 // Convert to conditional expression if (type == typeof(TypedElementOnSourceNode) || type == typeof(ITypedElement) || type == typeof(IShortPathGenerator)) -#pragma warning restore IDE0046 // Convert to conditional expression return new[] { this }; else return _source.Annotations(type); @@ -496,6 +501,6 @@ public IEnumerable Annotations(Type type) } [Obsolete("This class is used for internal purposes and is subject to change without notice. Don't use.")] - public delegate object AdditionalStructuralRule(ITypedElement node, IExceptionSource ies, object state); + public delegate object? AdditionalStructuralRule(ITypedElement node, IExceptionSource ies, object? state); } diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs index 133a303b39..f3b5128762 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/ScopedNodeTests.cs @@ -267,7 +267,7 @@ static bool CCDATypeNameMapper(string typeName, out string canonical) Assert.AreEqual(1, assertXHtml.Count()); Assert.AreEqual("text", assertXHtml.First().Name); Assert.AreEqual("xhtml", assertXHtml.First().InstanceType); - Assert.AreEqual("text", assertXHtml.First().Location); + Assert.AreEqual("Section.text[0]", assertXHtml.First().Location); Assert.IsNotNull(assertXHtml.First().Value); diff --git a/src/Hl7.Fhir.ElementModel.Shared.Tests/TypedElementOnSourceNodeTests.cs b/src/Hl7.Fhir.ElementModel.Shared.Tests/TypedElementOnSourceNodeTests.cs index a27f5f50a1..0b34abbb7e 100644 --- a/src/Hl7.Fhir.ElementModel.Shared.Tests/TypedElementOnSourceNodeTests.cs +++ b/src/Hl7.Fhir.ElementModel.Shared.Tests/TypedElementOnSourceNodeTests.cs @@ -1,9 +1,11 @@ -using System; +using Hl7.Fhir.Model; +using System; using System.Linq; -using System.Threading.Tasks; using Hl7.Fhir.Serialization; using Hl7.Fhir.Specification; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using Task = System.Threading.Tasks.Task; namespace Hl7.Fhir.ElementModel.Tests { @@ -22,5 +24,27 @@ public async Task TestExceptionComplexTypeValue() var _ = typedBundle.Children("entry").First().Value; } + + private SourceNode testPatient => SourceNode.Node("Patient", + SourceNode.Resource("contained", "Observation", SourceNode.Valued("valueBoolean", "true")), + SourceNode.Valued("active", "true", + SourceNode.Valued("id", "myId2"), + SourceNode.Node("extension", + SourceNode.Valued("url", "http://example.org/ext"), + SourceNode.Valued("valueString", "world!")))); + + private TypedElementOnSourceNode getTestPatient => (TypedElementOnSourceNode)testPatient.ToTypedElement(ModelInfo.ModelInspector, "Patient"); + + [TestMethod] + public void KnowsPath() + { + var tp = getTestPatient; + Assert.AreEqual("Patient", getTestPatient.Location); + Assert.AreEqual("Patient.contained[0].value[0]", getTestPatient.Children("contained").First().Children("value").First().Location); + Assert.AreEqual("Patient.active[0]", getTestPatient.Children("active").First().Location); + Assert.AreEqual("Patient.active[0].id[0]", getTestPatient.Children("active").First().Children("id").First().Location); + Assert.AreEqual("Patient.active[0].extension[0].url[0]", getTestPatient.Children("active").First().Children("extension").First().Children("url").First().Location); + Assert.AreEqual("Patient.active[0].extension[0].value[0]", getTestPatient.Children("active").First().Children("extension").First().Children("value").First().Location); + } } } diff --git a/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs b/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs index ce410988f2..6b15a13ac2 100644 --- a/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs +++ b/src/Hl7.Fhir.Serialization.Shared.Tests/RoundtripAllSerializers.cs @@ -28,12 +28,12 @@ public string RoundTripXml(string original) => engine.SerializeToXml( engine.DeserializeFromJson( engine.SerializeToJson( - engine.DeserializeFromXml(original)))); + engine.DeserializeFromXml(original)!))!); public string RoundTripJson(string original) => engine.SerializeToJson( engine.DeserializeFromXml( engine.SerializeToXml( - engine.DeserializeFromJson(original)))); + engine.DeserializeFromJson(original)!))!); } internal class TypedElementBasedRoundtripper(IStructureDefinitionSummaryProvider provider) : IRoundTripper @@ -249,7 +249,7 @@ public void TestMatchAndExactly(ZipArchiveEntry entry) ? NEW_POCO_ENGINE.DeserializeFromXml(input) : NEW_POCO_ENGINE.DeserializeFromJson(input); - var r2 = (Resource)resource.DeepCopy(); + var r2 = (Resource)resource!.DeepCopy(); Assert.IsTrue(resource.Matches(r2), "Serialization of " + name + " did not match output - Matches test"); Assert.IsTrue(resource.IsExactly(r2), diff --git a/src/Hl7.Fhir.Support.Poco.Tests/Rest/TransactionBuilderTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/Rest/TransactionBuilderTests.cs index b917d8ee77..d1034830ba 100644 --- a/src/Hl7.Fhir.Support.Poco.Tests/Rest/TransactionBuilderTests.cs +++ b/src/Hl7.Fhir.Support.Poco.Tests/Rest/TransactionBuilderTests.cs @@ -13,166 +13,165 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; -namespace Hl7.Fhir.Test +namespace Hl7.Fhir.Test; + +[TestClass] +public class TransactionBuilderTests { - [TestClass] - public class TransactionBuilderTests + [TestMethod] + public void TestBuild() + { + var p = new TestPatient(); + var b = new TransactionBuilder("http://myserver.org/fhir") + .Create(p) + .ResourceHistory("Patient", "7") + .Delete("Patient", "8") + .Read("Patient", "9", versionId: "bla") + .ToBundle(); + + Assert.AreEqual(4, b.Entry.Count); + + Assert.AreEqual(Bundle.HTTPVerb.POST, b.Entry[0].Request.Method); + Assert.AreEqual(p, b.Entry[0].Resource); + + Assert.AreEqual(Bundle.HTTPVerb.GET, b.Entry[1].Request.Method); + Assert.AreEqual("Patient/7/_history", b.Entry[1].Request.Url); + + Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[2].Request.Method); + Assert.AreEqual("Patient/8", b.Entry[2].Request.Url); + + Assert.AreEqual(Bundle.HTTPVerb.GET, b.Entry[3].Request.Method); + Assert.AreEqual("Patient/9", b.Entry[3].Request.Url); + Assert.AreEqual("W/\"bla\"", b.Entry[3].Request.IfNoneMatch); + } + + [TestMethod] + public void TestInteractionType() + { + // just try a few + var tx = new TransactionBuilder("http://myserver.org/fhir").ServerHistory(); + Assert.AreEqual(InteractionType.History, tx.ToBundle().Entry[0].Annotation()); + + tx = new TransactionBuilder("http://myserver.org/fhir").ServerOperation("$everything", null); + Assert.AreEqual(InteractionType.Operation, tx.ToBundle().Entry[0].Annotation()); + + var p = new TestPatient(); + tx = new TransactionBuilder("http://myserver.org/fhir").Create(p); + Assert.AreEqual(InteractionType.Create, tx.ToBundle().Entry[0].Annotation()); + + tx = new TransactionBuilder("http://myserver.org/fhir").Search(new SearchParams().Where("name=ewout"), resourceType: "Patient"); + Assert.AreEqual(InteractionType.Search, tx.ToBundle().Entry[0].Annotation()); + } + + + [TestMethod] + public void TestConditionalCreate() + { + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .ConditionalCreate(p, new SearchParams().Where("name=foobar")); + var b = tx.ToBundle(); + + Assert.AreEqual("name=foobar", b.Entry[0].Request.IfNoneExist); + } + + + [TestMethod] + public void TestConditionalUpdate() + { + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .ConditionalUpdate(new SearchParams().Where("name=foobar"), p, versionId: "314"); + var b = tx.ToBundle(); + + Assert.AreEqual("W/\"314\"", b.Entry[0].Request.IfMatch); + } + + /// + /// Unit test to prove issue 536: + /// https://github.com/FirelyTeam/firely-net-sdk/issues/536 + /// + [TestMethod] + public void TestTransactionWithForwardSlash() + { + var tx2 = new TransactionBuilder("http://myserver.org/fhir/"); + var bundle = tx2.Get("@Patient/1").ToBundle(); + + var tx = new TransactionBuilder("http://myserver.org/fhir/") + .Transaction(bundle); + + var b = tx.ToBundle(); + Assert.IsFalse(b.Entry[0].Request.Url.EndsWith(@"/"), "Url cannot end with forward slash"); + } + + [TestMethod] + public void TestTransactionWithAbsoluteUri() + { + var patient = new TestPatient(); + var endpoint = "http://fhirtest.uhn.ca/baseDstu2"; + + var transaction = new TransactionBuilder(endpoint) + .Create(patient) + .Get("Patient/1"); + var bundle = transaction.ToBundle(); + bundle.Type = Bundle.BundleType.Transaction; + + Assert.AreEqual(2, bundle.Entry.Count); + Assert.IsFalse(bundle.Entry[0].Request.Url.StartsWith(endpoint), "Entries in the transaction bundle cannot contain absolute url."); + Assert.AreEqual("Patient", bundle.Entry[0].Request.Url, "Entry must be a relative url"); + } + + [TestMethod] + public void TransactionBuilderWithFullUrlTest() + { + var fullUrl = "http://myserver.org/fhir/123"; + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .ConditionalUpdate(new SearchParams().Where("name=foobar"), p, versionId: "314", fullUrl); + var bundle = tx.ToBundle(); + + bundle.Entry.Should().ContainSingle().Which.FullUrl.Should().Be(fullUrl); + + tx.Read("TestPatient", "123"); + + bundle = tx.ToBundle(); + + bundle.Entry.Skip(1).Should().ContainSingle().Which.FullUrl.Should().BeNull(); + + } + + [TestMethod] + public void TestConditionalDeleteWithIfmatch() + { + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .ConditionalDeleteSingle(new SearchParams().Where("name=foobar"), p.TypeName, versionId: "314"); + var b = tx.ToBundle(); + + Assert.AreEqual("W/\"314\"", b.Entry[0].Request.IfMatch); + } + + [TestMethod] + public void TestDeleteHistory() { - [TestMethod] - public void TestBuild() - { - var p = new TestPatient(); - var b = new TransactionBuilder("http://myserver.org/fhir") - .Create(p) - .ResourceHistory("Patient", "7") - .Delete("Patient", "8") - .Read("Patient", "9", versionId: "bla") - .ToBundle(); - - Assert.AreEqual(4, b.Entry.Count); - - Assert.AreEqual(Bundle.HTTPVerb.POST, b.Entry[0].Request.Method); - Assert.AreEqual(p, b.Entry[0].Resource); - - Assert.AreEqual(Bundle.HTTPVerb.GET, b.Entry[1].Request.Method); - Assert.AreEqual("Patient/7/_history", b.Entry[1].Request.Url); - - Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[2].Request.Method); - Assert.AreEqual("Patient/8", b.Entry[2].Request.Url); - - Assert.AreEqual(Bundle.HTTPVerb.GET, b.Entry[3].Request.Method); - Assert.AreEqual("Patient/9", b.Entry[3].Request.Url); - Assert.AreEqual("W/\"bla\"", b.Entry[3].Request.IfNoneMatch); - } - - [TestMethod] - public void TestInteractionType() - { - // just try a few - var tx = new TransactionBuilder("http://myserver.org/fhir").ServerHistory(); - Assert.AreEqual(InteractionType.History, tx.ToBundle().Entry[0].Annotation()); - - tx = new TransactionBuilder("http://myserver.org/fhir").ServerOperation("$everything", null); - Assert.AreEqual(InteractionType.Operation, tx.ToBundle().Entry[0].Annotation()); - - var p = new TestPatient(); - tx = new TransactionBuilder("http://myserver.org/fhir").Create(p); - Assert.AreEqual(InteractionType.Create, tx.ToBundle().Entry[0].Annotation()); - - tx = new TransactionBuilder("http://myserver.org/fhir").Search(new SearchParams().Where("name=ewout"), resourceType: "Patient"); - Assert.AreEqual(InteractionType.Search, tx.ToBundle().Entry[0].Annotation()); - } - - - [TestMethod] - public void TestConditionalCreate() - { - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .Create(p, new SearchParams().Where("name=foobar")); - var b = tx.ToBundle(); - - Assert.AreEqual("name=foobar", b.Entry[0].Request.IfNoneExist); - } - - - [TestMethod] - public void TestConditionalUpdate() - { - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .Update(new SearchParams().Where("name=foobar"), p, versionId: "314"); - var b = tx.ToBundle(); - - Assert.AreEqual("W/\"314\"", b.Entry[0].Request.IfMatch); - } - - /// - /// Unit test to prove issue 536: - /// https://github.com/FirelyTeam/firely-net-sdk/issues/536 - /// - [TestMethod] - public void TestTransactionWithForwardSlash() - { - var tx2 = new TransactionBuilder("http://myserver.org/fhir/"); - var bundle = tx2.Get("@Patient/1").ToBundle(); - - var tx = new TransactionBuilder("http://myserver.org/fhir/") - .Transaction(bundle); - - var b = tx.ToBundle(); - Assert.IsFalse(b.Entry[0].Request.Url.EndsWith(@"/"), "Url cannot end with forward slash"); - } - - [TestMethod] - public void TestTransactionWithAbsoluteUri() - { - var patient = new TestPatient(); - var endpoint = "http://fhirtest.uhn.ca/baseDstu2"; - - var transaction = new TransactionBuilder(endpoint) - .Create(patient) - .Get("Patient/1"); - var bundle = transaction.ToBundle(); - bundle.Type = Bundle.BundleType.Transaction; - - Assert.AreEqual(2, bundle.Entry.Count); - Assert.IsFalse(bundle.Entry[0].Request.Url.StartsWith(endpoint), "Entries in the transaction bundle cannot contain absolute url."); - Assert.AreEqual("Patient", bundle.Entry[0].Request.Url, "Entry must be a relative url"); - } - - [TestMethod] - public void TransactionBuilderWithFullUrlTest() - { - var fullUrl = "http://myserver.org/fhir/123"; - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .Update(new SearchParams().Where("name=foobar"), p, versionId: "314", fullUrl); - var bundle = tx.ToBundle(); - - bundle.Entry.Should().ContainSingle().Which.FullUrl.Should().Be(fullUrl); - - tx.Read("TestPatient", "123"); - - bundle = tx.ToBundle(); - - bundle.Entry.Skip(1).Should().ContainSingle().Which.FullUrl.Should().BeNull(); - - } - - [TestMethod] - public void TestConditionalDeleteWithIfmatch() - { - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .ConditionalDeleteSingle(new SearchParams().Where("name=foobar"), p.TypeName, versionId: "314"); - var b = tx.ToBundle(); - - Assert.AreEqual("W/\"314\"", b.Entry[0].Request.IfMatch); - } - - [TestMethod] - public void TestDeleteHistory() - { - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .DeleteHistory("Patient", "7"); - var b = tx.ToBundle(); + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .DeleteHistory("Patient", "7"); + var b = tx.ToBundle(); - Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[0].Request.Method); - Assert.AreEqual("Patient/7/_history", b.Entry[0].Request.Url); - } - - [TestMethod] - public void TestDeleteHistoryVersion() - { - var p = new TestPatient(); - var tx = new TransactionBuilder("http://myserver.org/fhir") - .DeleteHistoryVersion("Patient", "7", "1"); - var b = tx.ToBundle(); + Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[0].Request.Method); + Assert.AreEqual("Patient/7/_history", b.Entry[0].Request.Url); + } + + [TestMethod] + public void TestDeleteHistoryVersion() + { + var p = new TestPatient(); + var tx = new TransactionBuilder("http://myserver.org/fhir") + .DeleteHistoryVersion("Patient", "7", "1"); + var b = tx.ToBundle(); - Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[0].Request.Method); - Assert.AreEqual("Patient/7/_history/1", b.Entry[0].Request.Url); - } + Assert.AreEqual(Bundle.HTTPVerb.DELETE, b.Entry[0].Request.Method); + Assert.AreEqual("Patient/7/_history/1", b.Entry[0].Request.Url); } -} +} \ No newline at end of file