Tests don't have to be in the same directory anymore; add sanity check; add instruction generation to lua file output

This commit is contained in:
Pieter Vander Vennet 2020-05-20 16:19:59 +02:00
parent 7033751d91
commit 4597a7f9ff
6 changed files with 181 additions and 27 deletions

View file

@ -17,7 +17,7 @@ namespace AspectedRouting.IO.itinero1
/// A dictionary containing the implementation of basic functions
/// </summary>
/// <returns></returns>
private static IEnumerable<string> LoadFunctions(List<string> names)
private static IEnumerable<string> LoadFunctions(IEnumerable<string> names)
{
var imps = new List<string>();
@ -49,6 +49,7 @@ namespace AspectedRouting.IO.itinero1
deps.Add("unitTestProfile");
deps.Add("inv");
deps.Add("double_compare");
deps.Add("spoken_instructions");
var code = new List<string>();

View file

@ -422,7 +422,6 @@ namespace AspectedRouting.IO.jsonParser
{
var expr = GetTopLevelExpression(e, context);
var targetTypes = new List<Type>();
foreach (var t in expr.Types)
{

View file

@ -0,0 +1,127 @@
-- instruction generators
instruction_generators = {
{
applies_to = "", -- applies to all profiles when empty
generators = {
{
name = "start",
function_name = "get_start"
},
{
name = "stop",
function_name = "get_stop"
},
{
name = "roundabout",
function_name = "get_roundabout"
},
{
name = "turn",
function_name = "get_turn"
}
}
}
}
-- gets the first instruction
function get_start(route_position, language_reference, instruction)
if route_position.is_first() then
local direction = route_position.direction()
instruction.text = itinero.format(language_reference.get("Start {0}."), language_reference.get(direction));
instruction.shape = route_position.shape
return 1
end
return 0
end
-- gets the last instruction
function get_stop(route_position, language_reference, instruction)
if route_position.is_last() then
instruction.text = language_reference.get("Arrived at destination.");
instruction.shape = route_position.shape
return 1
end
return 0
end
-- gets a roundabout instruction
function get_roundabout(route_position, language_reference, instruction)
if route_position.attributes.junction == "roundabout" and
(not route_position.is_last()) then
local attributes = route_position.next().attributes
if attributes.junction then
else
local exit = 1
local count = 1
local previous = route_position.previous()
while previous and previous.attributes.junction == "roundabout" do
local branches = previous.branches
if branches then
branches = branches.get_traversable()
if branches.count > 0 then
exit = exit + 1
end
end
count = count + 1
previous = previous.previous()
end
instruction.text = itinero.format(language_reference.get("Take the {0}th exit at the next roundabout."), "" .. exit)
if exit == 1 then
instruction.text = itinero.format(language_reference.get("Take the first exit at the next roundabout."))
elseif exit == 2 then
instruction.text = itinero.format(language_reference.get("Take the second exit at the next roundabout."))
elseif exit == 3 then
instruction.text = itinero.format(language_reference.get("Take the third exit at the next roundabout."))
end
instruction.type = "roundabout"
instruction.shape = route_position.shape
return count
end
end
return 0
end
-- gets a turn
function get_turn(route_position, language_reference, instruction)
local relative_direction = route_position.relative_direction().direction
local turn_relevant = false
local branches = route_position.branches
if branches then
branches = branches.get_traversable()
if relative_direction == "straighton" and
branches.count >= 2 then
turn_relevant = true -- straight on at cross road
end
if relative_direction ~= "straighton" and
branches.count > 0 then
turn_relevant = true -- an actual normal turn
end
end
if relative_direction == "unknown" then
turn_relevant = false -- turn could not be calculated.
end
if turn_relevant then
local next = route_position.next()
local name = nil
if next then
name = next.attributes.name
end
if name then
instruction.text = itinero.format(language_reference.get("Go {0} on {1}."),
language_reference.get(relative_direction), name)
instruction.shape = route_position.shape
else
instruction.text = itinero.format(language_reference.get("Go {0}."),
language_reference.get(relative_direction))
instruction.shape = route_position.shape
end
return 1
end
return 0
end

View file

@ -14,7 +14,7 @@ namespace AspectedRouting
static class Program
{
public static IEnumerable<(AspectMetadata aspect, AspectTestSuite tests)> ParseAspects(
this IEnumerable<string> jsonFileNames, Context context)
this IEnumerable<string> jsonFileNames, List<string> testFileNames, Context context)
{
var aspects = new List<(AspectMetadata aspect, AspectTestSuite tests)>();
foreach (var file in jsonFileNames)
@ -22,22 +22,39 @@ namespace AspectedRouting
var fi = new FileInfo(file);
Console.WriteLine("Parsing " + file);
var aspect = JsonParser.AspectFromJson(context, File.ReadAllText(file), fi.Name);
if (aspect != null)
{
var testPath = fi.DirectoryName + "/" + aspect.Name + ".test.csv";
AspectTestSuite tests = null;
if (File.Exists(testPath))
{
tests = AspectTestSuite.FromString(aspect, File.ReadAllText(testPath));
}
if (aspect == null) continue;
aspects.Add((aspect, tests));
var testName = aspect.Name + ".test.csv";
var testPath = testFileNames.FindTest(testName);
AspectTestSuite tests = null;
if (!string.IsNullOrEmpty(testPath) && File.Exists(testPath))
{
tests = AspectTestSuite.FromString(aspect, File.ReadAllText(testPath));
}
aspects.Add((aspect, tests));
}
return aspects;
}
private static string FindTest(this IEnumerable<string> testFileNames, string testName)
{
var testPaths = testFileNames.Where(nm => nm.EndsWith(testName)).ToList();
if (testPaths.Count > 1)
{
Console.WriteLine("[WARNING] Multiple tests found for " + testName + ", using only one arbitrarily");
}
if (testPaths.Count > 0)
{
return testPaths.First();
}
return null;
}
private static LuaPrinter GenerateLua(Context context,
IEnumerable<(AspectMetadata aspect, AspectTestSuite tests)> aspects,
ProfileMetaData profile, List<ProfileTestSuite> profileTests)
@ -71,7 +88,7 @@ namespace AspectedRouting
}
private static IEnumerable<(ProfileMetaData profile, List<ProfileTestSuite> profileTests)> ParseProfiles(
IEnumerable<string> jsonFiles, Context context)
IEnumerable<string> jsonFiles, IReadOnlyCollection<string> testFiles, Context context)
{
var result = new List<(ProfileMetaData profile, List<ProfileTestSuite> profileTests)>();
foreach (var jsonFile in jsonFiles)
@ -87,13 +104,11 @@ namespace AspectedRouting
profile.SanityCheckProfile(context);
var profileFi = new FileInfo(jsonFile);
var profileTests = new List<ProfileTestSuite>();
foreach (var behaviourName in profile.Behaviours.Keys)
{
var path = profileFi.DirectoryName + "/" + profile.Name + "." + behaviourName +
".behaviour_test.csv";
if (File.Exists(path))
var path = testFiles.FindTest($"{profile.Name}.{behaviourName}.behaviour_test.csv");
if (path != null && File.Exists(path))
{
var test = ProfileTestSuite.FromString(context, profile, behaviourName,
File.ReadAllText(path));
@ -122,12 +137,13 @@ namespace AspectedRouting
var behaviour = profile.Behaviours.Keys.First();
do
{
Console.Write(behaviour + " > ");
Console.Write(profile.Name + "." + behaviour + " > ");
var read = Console.ReadLine();
if (read == null)
{
return; // End of stream has been reached
}
if (read.Equals("quit"))
{
return;
@ -143,10 +159,11 @@ namespace AspectedRouting
}
else
{
Console.WriteLine("Behaviour not found. Known behaviours are:\n "+string.Join("\n ", profile.Behaviours.Keys));
Console.WriteLine("Behaviour not found. Known behaviours are:\n " +
string.Join("\n ", profile.Behaviours.Keys));
}
continue;
}
@ -202,16 +219,19 @@ namespace AspectedRouting
var files = Directory.EnumerateFiles(inputDir, "*.json", SearchOption.AllDirectories)
.ToList();
var tests = Directory.EnumerateFiles(inputDir, "*test.csv", SearchOption.AllDirectories)
.ToList();
var context = new Context();
var aspects = ParseAspects(files, context);
var aspects = ParseAspects(files, tests, context);
foreach (var (aspect, _) in aspects)
{
context.AddFunction(aspect.Name, aspect);
}
var profiles = ParseProfiles(files, context);
var profiles = ParseProfiles(files, tests, context);
// With everything parsed and typechecked, time for tests
@ -238,9 +258,8 @@ namespace AspectedRouting
File.WriteAllText(outputDir + "/" + profile.Name + ".lua", luaPrinter.ToLua());
}
Repl(context,
profiles.First(p => p.profile.Name.Equals("rollerskate")).profile);
Repl(context,
profiles.First(p => p.profile.Name.Equals("bicycle")).profile);
}
}
}

View file

@ -26,7 +26,7 @@ namespace AspectedRouting.Tests
"oneway "+Oneway,
"speed "+Speed,
"priority "+Priority,
"because "+PriorityExplanation
"because \n "+PriorityExplanation
);
}
}

View file

@ -77,12 +77,20 @@ namespace AspectedRouting.Tests
weight = double.Parse(testData[3]);
}
var expected = new ProfileResult(
testData[0],
testData[1],
speed,
weight
);
if (expected.Priority == 0 && expected.Access != "no")
{
throw new ArgumentException("A priority of zero is interpreted as 'no access' - don't use it");
}
var vals = testData.GetRange(4, testData.Count - 4);
var tags = new Dictionary<string, string>();
for (int i = 0; i < keys.Count; i++)