Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Schema.Test/SchemaCommandLineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,34 @@ public void TestGeneratorOptionSelectsOneByName()
Assert.IsTrue(unmatched.Error.Contains("no code generator named 'Cpp'", StringComparison.Ordinal), unmatched.Error);
}

[TestMethod]
[DataRow("--generator")]
[DataRow("--generator=")]
[DataRow("--generator", "--verbose")]
public void TestGeneratorOptionWithoutANameFailsAndWritesNothing(params string[] option)
{
string path = WriteSchema("noname.schema.json", ValidSchema);
Result result = Run(["generate", path, .. option]);

Assert.AreEqual(SchemaCommandLine.Failure, result.ExitCode, result.Output);
Assert.IsTrue(result.Error.Contains("'--generator' needs a code generator name", StringComparison.Ordinal), result.Error);
Assert.IsFalse(Directory.Exists(Path.Combine(workingDirectory, "out")), "Nothing should have been written.");
}

[TestMethod]
public void TestGeneratorOptionAcceptsTheEqualsForm()
{
string path = WriteSchema("equals.schema.json", ValidSchema);

Result matched = Run("generate", path, "--generator=CSharp");
Assert.AreEqual(SchemaCommandLine.Success, matched.ExitCode, matched.Error);
Assert.IsTrue(File.Exists(Path.Combine(workingDirectory, "out", "Item.g.cs")), matched.Output);

Result unmatched = Run("generate", path, "--generator=Cpp");
Assert.AreEqual(SchemaCommandLine.Failure, unmatched.ExitCode);
Assert.IsTrue(unmatched.Error.Contains("no code generator named 'Cpp'", StringComparison.Ordinal), unmatched.Error);
}

[TestMethod]
public void TestOptionsDoNotGetMistakenForTheSchemaPath()
{
Expand Down
50 changes: 45 additions & 5 deletions Schema/Cli/SchemaCommandLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,14 @@ private static int UnknownCommand(string command, TextWriter output, TextWriter

private static int Generate(string[] args, TextWriter output, TextWriter error)
{
if (!TryLoad(args, error, out Models.Schema? schema, out string? schemaPath))
// Read the filter before anything is loaded or written: a filter that cannot be read must
// fail the command, never fall back to running every generator.
if (!TryGetGeneratorFilter(args, error, out string? only)
|| !TryLoad(args, error, out Models.Schema? schema, out string? schemaPath))
{
return Failure;
}

string? only = GetOption(args, GeneratorOption);
List<SchemaCodeGenerator> generators = [.. schema.CodeGenerators
.Where(g => only is null || string.Equals(g.Name, only, StringComparison.OrdinalIgnoreCase))];

Expand Down Expand Up @@ -230,9 +232,47 @@ private static bool TryLoad(
private static bool TakesAValue(string option) =>
string.Equals(option, GeneratorOption, StringComparison.OrdinalIgnoreCase);

private static string? GetOption(string[] args, string name)
/// <summary>
/// Reads the <c>--generator</c> filter, written either as <c>--generator Name</c> or
/// <c>--generator=Name</c>.
/// </summary>
/// <returns>
/// <see langword="false"/> when the option is present without a name. <paramref name="name"/> is
/// <see langword="null"/> only when the option is absent, which is the one case that means every
/// generator.
/// </returns>
private static bool TryGetGeneratorFilter(string[] args, TextWriter error, out string? name)
{
int index = Array.FindIndex(args, a => string.Equals(a, name, StringComparison.OrdinalIgnoreCase));
return index >= 0 && index + 1 < args.Length ? args[index + 1] : null;
name = null;
string prefix = GeneratorOption + "=";

for (int index = 0; index < args.Length; index++)
{
string argument = args[index];
if (string.Equals(argument, GeneratorOption, StringComparison.OrdinalIgnoreCase))
{
// A following option is not a name: "--generator --verbose" lost its value.
name = index + 1 < args.Length && !args[index + 1].StartsWith('-') ? args[index + 1] : null;
}
else if (argument.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
name = argument[prefix.Length..];
}
else
{
continue;
}

if (string.IsNullOrWhiteSpace(name))
{
error.WriteLine($"'{GeneratorOption}' needs a code generator name.");
name = null;
return false;
}

return true;
}

return true;
}
}
Loading