Skip to content

Commit 8a4d511

Browse files
committed
Add tests for anonymization and edge case handling
Added multiple test methods to validate anonymization logic: - `GetSamCommonLandsAsync_Generic_ShouldAnonymizeAddressAndLocationFields`: Ensures PII fields are anonymized while non-PII fields remain unchanged. - `GetSamCommonLandsByCommonCphAsync_ShouldAnonymizeAllCommonLands`: Verifies anonymization of all common lands for a given `COMMON_CPH`. - `GetSamCommonLandsByCommonCphAsync_ShouldHandleNullFields`: Confirms proper handling of null values in PII fields. - `GetSamCommonLandsByCommonCphAsync_ShouldNotAnonymizePlaceholderPremisesName`: Ensures placeholder values like `"-"` are not anonymized. - `GetSamCommonLandsAsync_ShouldProduceDeterministicResults`: Validates deterministic anonymization for the same `COMMON_CPH`. - `GetSamCommonLandsAsync_ShouldPreserveNonPiiFields`: Confirms non-PII fields are preserved while PII fields are anonymized. - `GetSamCommonLandsAsync_ShouldReturnNull_WhenInnerReturnsNull`: Ensures `null` is returned when the inner client returns `null`. - `GetSamCommonLandsByCommonCphAsync_ShouldHandleEmptyList`: Verifies proper handling of empty list responses.
1 parent b209aea commit 8a4d511

1 file changed

Lines changed: 297 additions & 0 deletions

File tree

tests/KeeperData.Infrastructure.Tests.Unit/ApiClients/DataBridgeClientAnonymizerTests.cs

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,303 @@ public async Task Anonymization_ShouldLogErrorAndContinue_WhenOneItemFails()
449449
result[1].STREET.Should().NotBe("Good Street");
450450
}
451451

452+
[Fact]
453+
public async Task GetSamCommonLandsAsync_Generic_ShouldAnonymizeAddressAndLocationFields()
454+
{
455+
// Arrange
456+
var commonLands = new List<SamCommonLand>
457+
{
458+
new()
459+
{
460+
COMMON_CPH = "00/000/0001",
461+
MAIN_CPH = "-",
462+
PREMISES_NAME = "Smiths Common Land",
463+
ADDRESS_LINE_1 = "123 Real Street",
464+
ADDRESS_LINE_2 = "Flat 5",
465+
ADDRESS_LINE_3 = "Manchester",
466+
POSTCODE = "M20 2XY",
467+
EASTING = "422473",
468+
NORTHING = "569204"
469+
}
470+
};
471+
472+
var response = new DataBridgeResponse<SamCommonLand>
473+
{
474+
CollectionName = "commonlands",
475+
Count = 1,
476+
TotalCount = 1,
477+
Data = commonLands
478+
};
479+
480+
_innerClient.GetSamCommonLandsAsync<SamCommonLand>(10, 0, null, null, null, Arg.Any<CancellationToken>())
481+
.Returns(response);
482+
483+
// Act
484+
var result = await _sut.GetSamCommonLandsAsync<SamCommonLand>(10, 0, cancellationToken: CancellationToken.None);
485+
486+
// Assert
487+
result.Should().NotBeNull();
488+
result!.Data.Should().HaveCount(1);
489+
490+
var anonymized = result.Data[0];
491+
492+
// Non-PII fields should remain unchanged
493+
anonymized.COMMON_CPH.Should().Be("00/000/0001");
494+
anonymized.MAIN_CPH.Should().Be("-");
495+
496+
// PII fields should be anonymized
497+
anonymized.PREMISES_NAME.Should().NotBe("Smiths Common Land").And.NotBeNullOrWhiteSpace();
498+
anonymized.ADDRESS_LINE_1.Should().NotBe("123 Real Street").And.NotBeNullOrWhiteSpace();
499+
anonymized.ADDRESS_LINE_2.Should().NotBe("Flat 5").And.NotBeNullOrWhiteSpace();
500+
anonymized.ADDRESS_LINE_3.Should().NotBe("Manchester").And.NotBeNullOrWhiteSpace();
501+
anonymized.POSTCODE.Should().NotBe("M20 2XY").And.MatchRegex(@"^[A-Z]{2}\d \d[A-Z]{2}$");
502+
anonymized.EASTING.Should().NotBe("422473");
503+
int.Parse(anonymized.EASTING!).Should().BeInRange(100000, 999999);
504+
anonymized.NORTHING.Should().NotBe("569204");
505+
int.Parse(anonymized.NORTHING!).Should().BeInRange(200000, 999999);
506+
}
507+
508+
[Fact]
509+
public async Task GetSamCommonLandsByCommonCphAsync_ShouldAnonymizeAllCommonLands()
510+
{
511+
// Arrange
512+
var commonLands = new List<SamCommonLand>
513+
{
514+
new()
515+
{
516+
COMMON_CPH = "00/000/0001",
517+
MAIN_CPH = "-",
518+
PREMISES_NAME = "Original Common Land",
519+
ADDRESS_LINE_1 = "Original Street",
520+
POSTCODE = "AB12 3CD",
521+
EASTING = "123456",
522+
NORTHING = "654321"
523+
},
524+
new()
525+
{
526+
COMMON_CPH = "00/000/0001",
527+
MAIN_CPH = "12/345/6789",
528+
CONTIGUOUS_COMMON = "Yes",
529+
START_DATE = "2020-01-01"
530+
}
531+
};
532+
533+
_innerClient.GetSamCommonLandsByCommonCphAsync("00/000/0001", Arg.Any<CancellationToken>())
534+
.Returns(commonLands);
535+
536+
// Act
537+
var result = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
538+
539+
// Assert
540+
result.Should().HaveCount(2);
541+
542+
var definitionRecord = result[0];
543+
var relationshipRecord = result[1];
544+
545+
// Definition record - PII should be anonymized
546+
definitionRecord.COMMON_CPH.Should().Be("00/000/0001");
547+
definitionRecord.MAIN_CPH.Should().Be("-");
548+
definitionRecord.PREMISES_NAME.Should().NotBe("Original Common Land").And.NotBeNullOrWhiteSpace();
549+
definitionRecord.ADDRESS_LINE_1.Should().NotBe("Original Street").And.NotBeNullOrWhiteSpace();
550+
definitionRecord.POSTCODE.Should().NotBe("AB12 3CD").And.MatchRegex(@"^[A-Z]{2}\d \d[A-Z]{2}$");
551+
definitionRecord.EASTING.Should().NotBe("123456");
552+
definitionRecord.NORTHING.Should().NotBe("654321");
553+
554+
// Relationship record - non-PII fields should remain unchanged
555+
relationshipRecord.COMMON_CPH.Should().Be("00/000/0001");
556+
relationshipRecord.MAIN_CPH.Should().Be("12/345/6789");
557+
relationshipRecord.CONTIGUOUS_COMMON.Should().Be("Yes");
558+
relationshipRecord.START_DATE.Should().Be("2020-01-01");
559+
}
560+
561+
[Fact]
562+
public async Task GetSamCommonLandsByCommonCphAsync_ShouldHandleNullFields()
563+
{
564+
// Arrange
565+
var commonLands = new List<SamCommonLand>
566+
{
567+
new()
568+
{
569+
COMMON_CPH = "00/000/0001",
570+
MAIN_CPH = "-",
571+
PREMISES_NAME = null,
572+
ADDRESS_LINE_1 = null,
573+
ADDRESS_LINE_2 = null,
574+
ADDRESS_LINE_3 = null,
575+
POSTCODE = null,
576+
EASTING = null,
577+
NORTHING = null
578+
}
579+
};
580+
581+
_innerClient.GetSamCommonLandsByCommonCphAsync("00/000/0001", Arg.Any<CancellationToken>())
582+
.Returns(commonLands);
583+
584+
// Act
585+
var result = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
586+
587+
// Assert
588+
result.Should().HaveCount(1);
589+
590+
var anonymized = result[0];
591+
anonymized.PREMISES_NAME.Should().BeNull();
592+
anonymized.ADDRESS_LINE_1.Should().BeNull();
593+
anonymized.ADDRESS_LINE_2.Should().BeNull();
594+
anonymized.ADDRESS_LINE_3.Should().BeNull();
595+
anonymized.POSTCODE.Should().BeNull();
596+
anonymized.EASTING.Should().BeNull();
597+
anonymized.NORTHING.Should().BeNull();
598+
}
599+
600+
[Fact]
601+
public async Task GetSamCommonLandsByCommonCphAsync_ShouldNotAnonymizePlaceholderPremisesName()
602+
{
603+
// Arrange
604+
var commonLands = new List<SamCommonLand>
605+
{
606+
new()
607+
{
608+
COMMON_CPH = "00/000/0001",
609+
MAIN_CPH = "-",
610+
PREMISES_NAME = "-",
611+
ADDRESS_LINE_1 = "Real Address"
612+
}
613+
};
614+
615+
_innerClient.GetSamCommonLandsByCommonCphAsync("00/000/0001", Arg.Any<CancellationToken>())
616+
.Returns(commonLands);
617+
618+
// Act
619+
var result = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
620+
621+
// Assert
622+
result.Should().HaveCount(1);
623+
result[0].PREMISES_NAME.Should().Be("-");
624+
result[0].ADDRESS_LINE_1.Should().NotBe("Real Address");
625+
}
626+
627+
[Fact]
628+
public async Task GetSamCommonLandsAsync_ShouldProduceDeterministicResults()
629+
{
630+
// Arrange
631+
var commonLands1 = new List<SamCommonLand>
632+
{
633+
new()
634+
{
635+
COMMON_CPH = "00/000/0001",
636+
MAIN_CPH = "-",
637+
ADDRESS_LINE_1 = "Street 1",
638+
PREMISES_NAME = "Name 1"
639+
}
640+
};
641+
642+
var commonLands2 = new List<SamCommonLand>
643+
{
644+
new()
645+
{
646+
COMMON_CPH = "00/000/0001",
647+
MAIN_CPH = "-",
648+
ADDRESS_LINE_1 = "Different Street",
649+
PREMISES_NAME = "Different Name"
650+
}
651+
};
652+
653+
_innerClient.GetSamCommonLandsByCommonCphAsync("00/000/0001", Arg.Any<CancellationToken>())
654+
.Returns(commonLands1, commonLands2);
655+
656+
// Act
657+
var result1 = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
658+
var result2 = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
659+
660+
// Assert - Same COMMON_CPH should produce same anonymized values
661+
result1[0].ADDRESS_LINE_1.Should().Be(result2[0].ADDRESS_LINE_1);
662+
result1[0].PREMISES_NAME.Should().Be(result2[0].PREMISES_NAME);
663+
}
664+
665+
[Fact]
666+
public async Task GetSamCommonLandsAsync_ShouldPreserveNonPiiFields()
667+
{
668+
// Arrange
669+
var commonLands = new List<SamCommonLand>
670+
{
671+
new()
672+
{
673+
BATCH_ID = 123,
674+
CHANGE_TYPE = "I",
675+
COMMON_CPH = "00/000/0001",
676+
MAIN_CPH = "12/345/6789",
677+
BUSINESS_USAGE = "Common Land",
678+
LOCAL_AUTH_NAME = "Test Council",
679+
COUNTRY = "England",
680+
CONTIGUOUS_COMMON = "Yes",
681+
START_DATE = "2020-01-01",
682+
END_DATE = "2024-12-31",
683+
ADDRESS_LINE_1 = "Secret Address",
684+
PREMISES_NAME = "Secret Name"
685+
}
686+
};
687+
688+
var response = new DataBridgeResponse<SamCommonLand>
689+
{
690+
CollectionName = "commonlands",
691+
Count = 1,
692+
Data = commonLands
693+
};
694+
695+
_innerClient.GetSamCommonLandsAsync<SamCommonLand>(10, 0, null, null, null, Arg.Any<CancellationToken>())
696+
.Returns(response);
697+
698+
// Act
699+
var result = await _sut.GetSamCommonLandsAsync<SamCommonLand>(10, 0, cancellationToken: CancellationToken.None);
700+
701+
// Assert
702+
var anonymized = result!.Data[0];
703+
704+
// Non-PII fields preserved
705+
anonymized.BATCH_ID.Should().Be(123);
706+
anonymized.CHANGE_TYPE.Should().Be("I");
707+
anonymized.COMMON_CPH.Should().Be("00/000/0001");
708+
anonymized.MAIN_CPH.Should().Be("12/345/6789");
709+
anonymized.BUSINESS_USAGE.Should().Be("Common Land");
710+
anonymized.LOCAL_AUTH_NAME.Should().Be("Test Council");
711+
anonymized.COUNTRY.Should().Be("England");
712+
anonymized.CONTIGUOUS_COMMON.Should().Be("Yes");
713+
anonymized.START_DATE.Should().Be("2020-01-01");
714+
anonymized.END_DATE.Should().Be("2024-12-31");
715+
716+
// PII fields anonymized
717+
anonymized.ADDRESS_LINE_1.Should().NotBe("Secret Address");
718+
anonymized.PREMISES_NAME.Should().NotBe("Secret Name");
719+
}
720+
721+
[Fact]
722+
public async Task GetSamCommonLandsAsync_ShouldReturnNull_WhenInnerReturnsNull()
723+
{
724+
// Arrange
725+
_innerClient.GetSamCommonLandsAsync<SamCommonLand>(10, 0, null, null, null, Arg.Any<CancellationToken>())
726+
.Returns((DataBridgeResponse<SamCommonLand>?)null);
727+
728+
// Act
729+
var result = await _sut.GetSamCommonLandsAsync<SamCommonLand>(10, 0, cancellationToken: CancellationToken.None);
730+
731+
// Assert
732+
result.Should().BeNull();
733+
}
734+
735+
[Fact]
736+
public async Task GetSamCommonLandsByCommonCphAsync_ShouldHandleEmptyList()
737+
{
738+
// Arrange
739+
_innerClient.GetSamCommonLandsByCommonCphAsync("00/000/0001", Arg.Any<CancellationToken>())
740+
.Returns([]);
741+
742+
// Act
743+
var result = await _sut.GetSamCommonLandsByCommonCphAsync("00/000/0001", CancellationToken.None);
744+
745+
// Assert
746+
result.Should().NotBeNull().And.BeEmpty();
747+
}
748+
452749
private static SamCphHolder CreateSamCphHolder() => new()
453750
{
454751
PARTY_ID = "P001",

0 commit comments

Comments
 (0)