Skip to content

Commit

Permalink
Merge pull request #903 from DFE-Digital/feature/179446-bulk-edit-fix…
Browse files Browse the repository at this point in the history
…es-2

Added validation for blank or empty files and project id duplication
  • Loading branch information
sukhybhullar-nimble authored Oct 11, 2024
2 parents 243d6e3 + b2bb673 commit 5749d4b
Show file tree
Hide file tree
Showing 16 changed files with 261 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task BasicValidationTest()
FileRowIndex = 1,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId.ToString() },
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate},
}
}
Expand All @@ -71,8 +71,8 @@ public async Task BasicValidationTest()
new()
{
ColumnIndex = 0,
CurrentValue = projectId.ToString(),
NewValue = projectId.ToString()
CurrentValue = projectId,
NewValue = projectId
}
,
new()
Expand Down Expand Up @@ -111,7 +111,7 @@ public async Task BasicSaveTest()
FileRowIndex = 1,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId.ToString() },
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate.ToString("dd/MM/yyyy")},
}
}
Expand Down Expand Up @@ -171,7 +171,7 @@ public async Task ProjectIDMissingTest()
FileRowIndex = 2,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId.ToString() },
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate },
}
}
Expand Down Expand Up @@ -212,8 +212,8 @@ public async Task ProjectIDMissingTest()
new()
{
ColumnIndex = 0,
CurrentValue = projectId.ToString(),
NewValue = projectId.ToString(),
CurrentValue = projectId,
NewValue = projectId,
},
new()
{
Expand All @@ -225,6 +225,130 @@ public async Task ProjectIDMissingTest()
}



[Fact]
public async Task ProjectIDDuplicatedTest()
{
var project = DatabaseModelBuilder.BuildProject();
var correctProject = DatabaseModelBuilder.BuildProject();

var projectId = project.ProjectStatusProjectId;
var ExistingOpeningDate = project.ProjectStatusActualOpeningDate;
var NewOpeningDate = "01/01/2021";

var correctProjectId = correctProject.ProjectStatusProjectId;

using var context = _testFixture.GetContext();
context.Kpi.Add(project);
context.Kpi.Add(correctProject);
await context.SaveChangesAsync();

var bulkValidateRequest = new BulkEditRequest
{
Headers = new List<HeaderInfo>
{
new HeaderInfo { Name = HeaderNames.ProjectId, Index = 0 },
new HeaderInfo { Name = HeaderNames.OpeningDate, Index = 2 },
},
Rows = new List<RowInfo>
{
new RowInfo
{
FileRowIndex = 1,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate },
}
},
new RowInfo
{
FileRowIndex = 2,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = correctProjectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate },
}
},
new RowInfo
{
FileRowIndex = 3,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 2, Value = NewOpeningDate },
}
}
}
};

var response = await _testFixture.Client.PostAsync($"api/v1/bulkedit/validate", bulkValidateRequest.ConvertToJson());

response.EnsureSuccessStatusCode();

var result = await response.Content.ReadFromJsonAsync<ApiSingleResponseV2<BulkEditValidateResponse>>();

result.Data.Headers.Should().BeEquivalentTo(bulkValidateRequest.Headers);

var resultRow = result.Data.ValidationResultRows.FirstOrDefault(x => x.FileRowIndex == 1);

resultRow.Columns.Should().BeEquivalentTo(new List<ValueChangeInfo>
{
new()
{
ColumnIndex = 0,
CurrentValue = projectId,
NewValue = projectId,
Error = "The project ID must be unique"
},
new()
{
ColumnIndex = 2,
CurrentValue = ExistingOpeningDate.Value.ToString("dd/MM/yyyy"),
NewValue = NewOpeningDate
}
});

var resultValidRow = result.Data.ValidationResultRows.FirstOrDefault(x => x.FileRowIndex == 2);

resultValidRow.Columns.Should().BeEquivalentTo(new List<ValueChangeInfo>
{
new()
{
ColumnIndex = 0,
CurrentValue = correctProjectId,
NewValue = correctProjectId,
},
new()
{
ColumnIndex = 2,
CurrentValue = correctProject.ProjectStatusActualOpeningDate.Value.ToString("dd/MM/yyyy"),
NewValue = NewOpeningDate
}
});

var resultDuplicatedRow = result.Data.ValidationResultRows.FirstOrDefault(x => x.FileRowIndex == 3);

resultDuplicatedRow.Columns.Should().BeEquivalentTo(new List<ValueChangeInfo>
{
new()
{
ColumnIndex = 0,
CurrentValue = projectId,
NewValue = projectId,
Error = "The project ID must be unique"
},
new()
{
ColumnIndex = 2,
CurrentValue = ExistingOpeningDate.Value.ToString("dd/MM/yyyy"),
NewValue = NewOpeningDate
}
});
}



[Fact]
public async Task LocalAuthorityValidationTest()
{
Expand Down Expand Up @@ -440,7 +564,7 @@ public async Task IfBlankDoNotChangeTest()
FileRowIndex = 1,
Columns = new List<ColumnInfo>
{
new ColumnInfo { ColumnIndex = 0, Value = projectId.ToString() },
new ColumnInfo { ColumnIndex = 0, Value = projectId },
new ColumnInfo { ColumnIndex = 1, Value = string.Empty },
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Dfe.ManageFreeSchoolProjects.API.Tests.UseCases.BulkEdit
{
internal record TestDto: IBulkEditDto
internal record TestDto : IBulkEditDto
{
public string ProjectId { get; set; }
public string TestData { get; set; }
Expand Down Expand Up @@ -79,11 +79,11 @@ public List<HeaderType<TestDto>> GetHeaders()
{
return new()
{
new() { Name = ProjectId, Type = new TestProjectIdValidation(), DataInteraction = new TestInteraction(x => x.ProjectId, (x, t) => t.ProjectId = x) },
new() { Name = HeaderOneName, Type = new TestValidation(), DataInteraction = new TestInteraction(x => x.TestData, (x, t) => t.TestData = x) },
new() { Name = HeaderTwoName, Type = new TestValidation(), DataInteraction = new TestInteraction(x => x.OtherTestData, (x, t) => t.OtherTestData = x) },
new() { Name = HeaderData, Type = new DataDependencyValidation(), DataInteraction = new TestInteraction(x => x.DependantTestData, (x, t) => t.DependantTestData = x) },
new() { Name = FormattedName, Type = new TestValidation(), DataInteraction = new TestFormattedInteraction(x => x.TestData, (x, t) => t.TestData = x) },
new() { Name = ProjectId, Validation = new TestProjectIdValidation(), DataInteraction = new TestInteraction(x => x.ProjectId, (x, t) => t.ProjectId = x) },
new() { Name = HeaderOneName, Validation = new TestValidation(), DataInteraction = new TestInteraction(x => x.TestData, (x, t) => t.TestData = x) },
new() { Name = HeaderTwoName, Validation = new TestValidation(), DataInteraction = new TestInteraction(x => x.OtherTestData, (x, t) => t.OtherTestData = x) },
new() { Name = HeaderData, Validation = new DataDependencyValidation(), DataInteraction = new TestInteraction(x => x.DependantTestData, (x, t) => t.DependantTestData = x) },
new() { Name = FormattedName, Validation = new TestValidation(), DataInteraction = new TestFormattedInteraction(x => x.TestData, (x, t) => t.TestData = x) },
};
}
}
Expand All @@ -93,7 +93,7 @@ internal class TestProjectIdValidation : IValidationCommand<TestDto>
internal const string ValidationMessage = "TriggeredValidation";
internal const string ValidInput = "Valid";

public ValidationResult Execute(TestDto data, string value)
public ValidationResult Execute(ValidationCommandParameters<TestDto> parameters)
{
return new ValidationResult()
{
Expand All @@ -107,12 +107,12 @@ internal class TestValidation : IValidationCommand<TestDto>
internal const string ValidationMessage = "TriggeredValidation";
internal const string ValidInput = "Valid";

public ValidationResult Execute(TestDto data, string value)
public ValidationResult Execute(ValidationCommandParameters<TestDto> parameters)
{
return new ValidationResult()
{
IsValid = value == ValidInput,
ErrorMessage = value == ValidInput ? null : ValidationMessage
IsValid = parameters.Value == ValidInput,
ErrorMessage = parameters.Value == ValidInput ? null : ValidationMessage
};
}
}
Expand All @@ -122,12 +122,12 @@ internal class DataDependencyValidation : IValidationCommand<TestDto>
{
internal const string DataValidationMessage = "Triggered data validation";

public ValidationResult Execute(TestDto data, string value)
public ValidationResult Execute(ValidationCommandParameters<TestDto> parameters)
{
return new ValidationResult()
{
IsValid = data.DataForValidation == value,
ErrorMessage = data.DataForValidation == value ? null : DataValidationMessage
IsValid = parameters.Data.DataForValidation == parameters.Value,
ErrorMessage = parameters.Data.DataForValidation == parameters.Value ? null : DataValidationMessage
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class DateValidationCommandTests
public void DateValidationFails(string date, string error)
{
var dateValidation = new DateValidationCommand();
var validationResult = dateValidation.Execute(null, date);
var validationResult = dateValidation.Execute(new() { Data = null, Value = date });

validationResult.IsValid.Should().BeFalse();
validationResult.ErrorMessage.Should().Be(error);
Expand All @@ -27,7 +27,7 @@ public void DateValidationFails(string date, string error)
public void DateValidationPasses(string date)
{
var dateValidation = new DateValidationCommand();
var validationResult = dateValidation.Execute(null, date);
var validationResult = dateValidation.Execute(new() { Data = null, Value = date });

validationResult.IsValid.Should().BeTrue();
validationResult.ErrorMessage.Should().BeNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public void Execute_WhenValidLACode_ReturnsValidResult()
});

var command = new LACodeValidationCommand(localAuthorityCache);

// Act
var result = command.Execute(null, "123");
var result = command.Execute(new() { Data = null, Value = "123"});

// Assert
result.IsValid.Should().BeTrue();
Expand All @@ -53,7 +53,7 @@ public void Execute_WhenInvalidLACode_ReturnsInvalidResult()
var command = new LACodeValidationCommand(localAuthorityCache);

// Act
var result = command.Execute(null, "456");
var result = command.Execute(new() { Data = null, Value = "456" });

// Assert
result.IsValid.Should().BeFalse();
Expand All @@ -77,7 +77,7 @@ public void Execute_WhenInvalidShortLACode_ReturnsInvalidResult()
var command = new LACodeValidationCommand(localAuthorityCache);

// Act
var result = command.Execute(null, "12");
var result = command.Execute(new() { Data = null, Value = "12" });

// Assert
result.IsValid.Should().BeFalse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void StatusValidationFails(string status, string error)
{
var projectStatusValidation = new ProjectStatusValidationCommand();
var dto = new BulkEditDto { ApplicationWave = "Any Wave" };
var validationResult = projectStatusValidation.Execute(dto, status);
var validationResult = projectStatusValidation.Execute(new() { Data = dto, Value = status });

validationResult.IsValid.Should().BeFalse();
validationResult.ErrorMessage.Should().Be(error);
Expand All @@ -41,7 +41,7 @@ public void StatusValidationPasses(string status)
{
var projectStatusValidation = new ProjectStatusValidationCommand();
var dto = new BulkEditDto { ApplicationWave = "Any Wave" };
var validationResult = projectStatusValidation.Execute(dto, status);
var validationResult = projectStatusValidation.Execute(new() { Data = dto, Value = status });

validationResult.IsValid.Should().BeTrue();
validationResult.ErrorMessage.Should().BeNull();
Expand All @@ -65,7 +65,7 @@ public void PresumptionFailsOnCertainStatus(string status, bool pass)
{
var projectStatusValidation = new ProjectStatusValidationCommand();
var dto = new BulkEditDto { ApplicationWave = "FS - Presumption" };
var validationResult = projectStatusValidation.Execute(dto, status);
var validationResult = projectStatusValidation.Execute(new() { Data = dto, Value = status });

validationResult.IsValid.Should().Be(pass);

Expand Down Expand Up @@ -98,7 +98,7 @@ public void PresumptionFailsOnCertainStatus(string status, bool pass)
public void IgnoresProjectIfNotFoundCertainStatus(string status, bool pass)
{
var projectStatusValidation = new ProjectStatusValidationCommand();
var validationResult = projectStatusValidation.Execute(null, status);
var validationResult = projectStatusValidation.Execute(new() { Data = null, Value = status });

validationResult.IsValid.Should().Be(pass);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ public List<HeaderType<BulkEditDto>> GetHeaders()
{
return new List<HeaderType<BulkEditDto>>
{
new() { Name = HeaderNames.ProjectId, Type = new ProjectIdValidationCommand(), DataInteraction = new ProjectIdInteraction() },
new() { Name = HeaderNames.OpeningDate, Type = new DateValidationCommand(), DataInteraction = new OpeningDateInteraction() },
new() { Name = HeaderNames.ProjectStatus, Type = new ProjectStatusValidationCommand(), DataInteraction = new ProjectStatusInteraction() },
new() { Name = HeaderNames.LocalAuthority, Type = new LACodeValidationCommand(localAuthorityCache), DataInteraction = new LACodeInteraction(localAuthorityCache) },
new() { Name = HeaderNames.ProjectId, Validation = new ProjectIdValidationCommand(), DataInteraction = new ProjectIdInteraction() },
new() { Name = HeaderNames.OpeningDate, Validation = new DateValidationCommand(), DataInteraction = new OpeningDateInteraction() },
new() { Name = HeaderNames.ProjectStatus, Validation = new ProjectStatusValidationCommand(), DataInteraction = new ProjectStatusInteraction() },
new() { Name = HeaderNames.LocalAuthority, Validation = new LACodeValidationCommand(localAuthorityCache), DataInteraction = new LACodeInteraction(localAuthorityCache) },

};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ public async Task<BulkEditValidateResponse> Execute(BulkEditRequest request)
}

var header = headerMap[column.ColumnIndex];
var validationResult = header.Type.Execute(currentRow, column.Value);
var validationResult = header.Validation.Execute(new ValidationCommandParameters<TDto>()
{
Value = column.Value,
Request = request,
CurrentRowIndex = row.FileRowIndex,
Data = currentRow
});
var currentValue = IsNotNullOrEmpty(currentRow) ? header.DataInteraction.GetFromDto(currentRow) : "";
if (!validationResult.IsValid)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public record HeaderType<T> where T : IBulkEditDto
{
public string Name { get; set; }

public IValidationCommand<T> Type { get; set; }
public IValidationCommand<T> Validation { get; set; }

public IHeaderDataInteraction<T> DataInteraction { get; set; }
}
Expand Down
Loading

0 comments on commit 5749d4b

Please sign in to comment.