Skip to content

Commit

Permalink
Merge pull request #119 from AndyTWF/active-runway-validation
Browse files Browse the repository at this point in the history
Active runway validation
  • Loading branch information
AndyTWF authored Jan 29, 2021
2 parents 5c0aa47 + 30afdb7 commit 3d8ebe3
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 3 deletions.
20 changes: 19 additions & 1 deletion src/Compiler/Model/ActiveRunway.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Compiler.Model
using System;

namespace Compiler.Model
{
public class ActiveRunway : AbstractCompilableElement
{
Expand All @@ -25,6 +27,22 @@ Comment inlineComment
*/
public int Mode { get; }

public override bool Equals(object obj)
{
return obj is ActiveRunway &&
Equals((ActiveRunway) obj);
}

protected bool Equals(ActiveRunway other)
{
return Identifier == other.Identifier && Airfield == other.Airfield && Mode == other.Mode;
}

public override int GetHashCode()
{
return HashCode.Combine(Identifier, Airfield, Mode);
}

public override string GetCompileData(SectorElementCollection elements)
{
return $"ACTIVE_RUNWAY:{this.Airfield}:{this.Identifier}:{this.Mode}";
Expand Down
36 changes: 36 additions & 0 deletions src/Compiler/Validate/AllActiveRunwaysMustBeUnique.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Linq;
using Compiler.Argument;
using Compiler.Error;
using Compiler.Event;
using Compiler.Model;

namespace Compiler.Validate
{
public class AllActiveRunwaysMustBeUnique: IValidationRule
{
public void Validate(SectorElementCollection sectorElements, CompilerArguments args, IEventLogger events)
{
var duplicates = sectorElements.ActiveRunways.GroupBy(
runway => runway
)
.Where(g => g.Count() > 1)
.ToList();

if (!duplicates.Any())
{
return;
}

foreach (var duplicate in duplicates)
{
ActiveRunway runway = duplicate.First();
events.AddEvent(
new ValidationRuleFailure(
$"Duplicate ACTIVE_RUNWAY {runway.Airfield}:{runway.Identifier}:{runway.Mode}",
runway
)
);
}
}
}
}
42 changes: 42 additions & 0 deletions src/Compiler/Validate/AllActiveRunwaysMustReferenceARunway.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Linq;
using Compiler.Argument;
using Compiler.Error;
using Compiler.Event;
using Compiler.Model;

namespace Compiler.Validate
{
public class AllActiveRunwaysMustReferenceARunway: IValidationRule
{
public void Validate(SectorElementCollection sectorElements, CompilerArguments args, IEventLogger events)
{
var missingRunways = sectorElements.ActiveRunways
.Where(
activeRunway => !sectorElements.Runways.Exists(runway => IsSameRunway(activeRunway, runway))
)
.ToList();

if (!missingRunways.Any())
{
return;
}

foreach (ActiveRunway runway in missingRunways)
{
events.AddEvent(
new ValidationRuleFailure(
$"Ruunway {runway.Airfield}/{runway.Identifier} specified in active runway does not exist",
runway
)
);
}
}

private bool IsSameRunway(ActiveRunway activeRunway, Runway runway)
{
return runway.AirfieldIcao == activeRunway.Airfield &&
(runway.FirstIdentifier == activeRunway.Identifier ||
runway.ReverseIdentifier == activeRunway.Identifier);
}
}
}
34 changes: 34 additions & 0 deletions src/Compiler/Validate/AllActiveRunwaysMustReferenceAnAirport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Linq;
using Compiler.Argument;
using Compiler.Error;
using Compiler.Event;
using Compiler.Model;

namespace Compiler.Validate
{
public class AllActiveRunwaysMustReferenceAnAirport: IValidationRule
{
public void Validate(SectorElementCollection sectorElements, CompilerArguments args, IEventLogger events)
{
var airports = sectorElements.Airports.Select(airport => airport.Icao).ToList();
var missingAirports = sectorElements.ActiveRunways
.Where(activeRunway => !airports.Contains(activeRunway.Airfield))
.ToList();

if (!missingAirports.Any())
{
return;
}

foreach (ActiveRunway runway in missingAirports)
{
events.AddEvent(
new ValidationRuleFailure(
$"Airport {runway.Airfield} specified in active runway does not exist",
runway
)
);
}
}
}
}
5 changes: 4 additions & 1 deletion src/Compiler/Validate/OutputValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ public class OutputValidator
new AllRunwaysMustReferenceAnAirport(),
new AllCoordinationPointsMustHaveValidDepartureRunways(),
new AllCoordinationPointsMustHaveValidArrivalRunways(),
new CentrelineColourIsDefined()
new CentrelineColourIsDefined(),
new AllActiveRunwaysMustReferenceAnAirport(),
new AllActiveRunwaysMustReferenceARunway(),
new AllActiveRunwaysMustBeUnique(),
};

public static void Validate(SectorElementCollection sectorElements, CompilerArguments args, IEventLogger events)
Expand Down
20 changes: 19 additions & 1 deletion tests/CompilerTest/Model/ActiveRunwayTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Xunit;
using System;
using Xunit;
using Compiler.Model;
using CompilerTest.Bogus.Factory;

Expand Down Expand Up @@ -46,5 +47,22 @@ public void TestItCompiles()
this.activeRunway.GetCompileData(new SectorElementCollection())
);
}

[Theory]
[InlineData("ABC", "DEF", 0, false)] // All different
[InlineData("EGBB", "34", 1, false)] // Different identifier
[InlineData("EGCC", "33", 1, false)] // Different airport
[InlineData("EGBB", "33", 0, false)] // Different mode
[InlineData("EGBB", "33", 1, true)] // All the same
public void TestEquality(string icao, string identifier, int mode, bool expected)
{
Assert.Equal(expected, activeRunway.Equals(ActiveRunwayFactory.Make(icao, identifier, mode)));
}

[Fact]
public void TestHash()
{
Assert.Equal(HashCode.Combine("33", "EGBB", 1), activeRunway.GetHashCode());
}
}
}
37 changes: 37 additions & 0 deletions tests/CompilerTest/Validate/AllActiveRunwaysMustBeUniqueTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Compiler.Validate;
using CompilerTest.Bogus.Factory;
using Xunit;

namespace CompilerTest.Validate
{
public class AllActiveRunwaysMustBeUniqueTest: AbstractValidatorTestCase
{
[Fact]
public void TestItFailsIfDuplicatesExist()
{
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27R", 1));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27R", 1));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27R", 0));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27L", 1));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27L", 1));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27L", 0));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27L", 0));
AssertValidationErrors(3);
}

[Fact]
public void TestItPassesOnNoDuplicates()
{
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27R", 1));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27R", 0));
sectorElements.Add(ActiveRunwayFactory.Make("EGLL", "27L", 0));
sectorElements.Add(ActiveRunwayFactory.Make("EGXY", "27L", 0));
AssertNoValidationErrors();
}

protected override IValidationRule GetValidationRule()
{
return new AllActiveRunwaysMustBeUnique();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Compiler.Validate;
using CompilerTest.Bogus.Factory;
using Xunit;

namespace CompilerTest.Validate
{
public class AllActiveRunwaysMustReferenceARunwayTest: AbstractValidatorTestCase
{
public AllActiveRunwaysMustReferenceARunwayTest()
{
sectorElements.Add(RunwayFactory.Make("EGLL", "09R", "27L"));
sectorElements.Add(RunwayFactory.Make("EGKK", "26L", "08R"));
}

[Theory]
[InlineData("EGLL", "27R")]
[InlineData("EGKK", "26R")]
[InlineData("EGLL", "abc")]
[InlineData("EGGD", "09")]
public void TestItFailsIfRunwayDoesntExist(string icao, string identifier)
{
sectorElements.Add(ActiveRunwayFactory.Make(icao, identifier));
AssertValidationErrors();
}

[Theory]
[InlineData("EGLL", "09R")] // First identifier match
[InlineData("EGKK", "26L")] // First identifier match
[InlineData("EGLL", "27L")] // Second identifier match
[InlineData("EGKK", "08R")] // Second identifier match
public void TestItPassesIfRunwayExists(string icao, string identifier)
{
sectorElements.Add(ActiveRunwayFactory.Make(icao, identifier));
AssertNoValidationErrors();
}

protected override IValidationRule GetValidationRule()
{
return new AllActiveRunwaysMustReferenceARunway();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Compiler.Validate;
using CompilerTest.Bogus.Factory;
using Xunit;

namespace CompilerTest.Validate
{
public class AllActiveRunwaysMustReferenceAnAirportTest: AbstractValidatorTestCase
{
public AllActiveRunwaysMustReferenceAnAirportTest()
{
sectorElements.Add(AirportFactory.Make("EGLL"));
sectorElements.Add(AirportFactory.Make("EGKK"));
sectorElements.Add(AirportFactory.Make("EGCC"));
}

[Fact]
public void TestItFailsIfAirportDoesntExist()
{
sectorElements.Add(ActiveRunwayFactory.Make("EGKB"));
sectorElements.Add(ActiveRunwayFactory.Make("EGLC"));
sectorElements.Add(ActiveRunwayFactory.Make("EGGD"));
AssertValidationErrors(3);
}

[Fact]
public void TestItPassesIfAirportExists()
{
sectorElements.Add(ActiveRunwayFactory.Make("EGLL"));
sectorElements.Add(ActiveRunwayFactory.Make("EGKK"));
sectorElements.Add(ActiveRunwayFactory.Make("EGCC"));
AssertNoValidationErrors();
}

protected override IValidationRule GetValidationRule()
{
return new AllActiveRunwaysMustReferenceAnAirport();
}
}
}

0 comments on commit 3d8ebe3

Please sign in to comment.