testing stuff

This commit is contained in:
Chris Watson 2023-01-27 11:26:11 -07:00
parent c90629ed3d
commit 97f88f9df8
10 changed files with 104 additions and 50 deletions

View File

@ -155,10 +155,10 @@ args._validation_errors # => {"age" => ["must be an integer"]}
ArgParser is designed to be configurable so it can handle a wide variety of use cases. As such, it includes several overridable methods which can be used to modify its behavior. These are:
- `on_validation_error` - called when a validation error occurs
- `on_unknown_attribute` - called when an unknown attribute is encountered
- `on_missing_attribute` - called when a required attribute is missing
- `on_conversion_error` - called when a value isn't able to be converted to the specified type
- `on_validation_error` - called when a validation error occurs; by default calls `add_validation_error` and then raises `ArgParser::ValidationError`
- `on_unknown_attribute` - called when an unknown attribute is encountered; by default raises `ArgParser::UnknownAttributeError`
- `on_missing_attribute` - called when a required attribute is missing; by default raises `ArgParser::MissingAttributeError`
- `on_conversion_error` - called when a value isn't able to be converted to the specified type; by default raises `ArgParser::ConversionError`
In addition, the way keys are parsed can be modified by overriding the `parse_key` method. By default, it simply removes one or two dashes from the beginning of the key. For example, `--name` becomes `name`, and `-n` becomes `n`.

View File

@ -1,37 +0,0 @@
require "./spec_helper"
Spectator.describe ArgParser do
context "supported arguments" do
let(args) { ["--name", "John Doe", "--age", "32", "--height", "163.2", "--is_human", "true", "--website", "https://example.com", "--id", "39aacd14-9e1b-11ed-91ad-b44506ca30d5"] }
let(parser) { TestSupportedArgs.new(args) }
it "parses name" do
expect(parser.name).to eq("John Doe")
end
it "parses age" do
expect(parser.age).to be_a(Int32)
expect(parser.age).to eq(32)
end
it "parses height" do
expect(parser.height).to be_a(Float64)
expect(parser.height).to eq(163.2)
end
it "parses is_human" do
expect(parser.is_human).to be_a(Bool)
expect(parser.is_human).to eq(true)
end
it "parses website" do
expect(parser.website).to be_a(URI)
expect(parser.website.to_s).to eq("https://example.com")
end
it "parses id" do
expect(parser.id).to be_a(UUID)
expect(parser.id.to_s).to eq("39aacd14-9e1b-11ed-91ad-b44506ca30d5")
end
end
end

View File

@ -19,3 +19,28 @@ struct TestSupportedArgs
getter id : UUID
end
enum Color
Red
Green
Blue
end
struct TestConverters
include ArgParser
@[ArgParser::Field(converter: ArgParser::CommaSeparatedArrayConverter(Int32))]
getter ids : Array(Int32)
@[ArgParser::Field(converter: ArgParser::EpochConverter)]
getter unix : Time
@[ArgParser::Field(converter: ArgParser::EpochMillisConverter, key: "unix-ms")]
getter unix_ms : Time
@[ArgParser::Field(converter: ArgParser::EnumNameConverter(Color))]
getter color : Color
@[ArgParser::Field(converter: ArgParser::EnumValueConverter(Color))]
getter ncolor : Color
end

View File

@ -0,0 +1,35 @@
require "../spec_helper"
Spectator.describe ArgParser do
let(args) { ["--name", "John Doe", "--age", "32", "--height", "163.2", "--is_human", "--website", "https://example.com", "--id", "39aacd14-9e1b-11ed-91ad-b44506ca30d5"] }
let(parser) { TestSupportedArgs.new(args) }
it "parses string values" do
expect(parser.name).to eq("John Doe")
end
it "parses int32 values" do
expect(parser.age).to be_a(Int32)
expect(parser.age).to eq(32)
end
it "parses float64 value" do
expect(parser.height).to be_a(Float64)
expect(parser.height).to eq(163.2)
end
it "parses boolean values" do
expect(parser.is_human).to be_a(Bool)
expect(parser.is_human).to eq(true)
end
it "parses uri values" do
expect(parser.website).to be_a(URI)
expect(parser.website.to_s).to eq("https://example.com")
end
it "parses uuid values" do
expect(parser.id).to be_a(UUID)
expect(parser.id.to_s).to eq("39aacd14-9e1b-11ed-91ad-b44506ca30d5")
end
end

View File

@ -0,0 +1,26 @@
require "../spec_helper"
Spectator.describe "ArgParser converters" do
let(args) { ["--ids", "1,2,3,4", "--unix", "1674843165", "--unix-ms", "1674843241159", "--color", "red", "--ncolor", "2"] }
let(parser) { TestConverters.new(args) }
it "converts comma separated list to array" do
expect(parser.ids).to eq [1, 2, 3, 4]
end
it "converts unix time to time" do
expect(parser.unix).to eq Time.unix(1674843165)
end
it "converts unix time to time" do
expect(parser.unix_ms).to eq Time.unix_ms(1674843241159)
end
it "converts string to color" do
expect(parser.color).to eq Color::Red
end
it "converts string to color" do
expect(parser.ncolor).to eq Color::Blue
end
end

View File

@ -84,7 +84,7 @@ module ArgParser
{% elsif value[:type] < Array %}
%var{name} ||= [] of {{value[:type].type_vars[0]}}
{% if value[:converter] %}
%var{name} << {{ value[:converter] }}.from_arg(value)
%var{name}.concat {{ value[:converter] }}.from_arg(value)
{% else %}
%var{name} << ::Union({{value[:type].type_vars[0]}}).from_arg(value)
{% end %}
@ -146,8 +146,6 @@ module ArgParser
%validator{name} = {{ validator.name(generic_args: false) }}.new({{ args.join(", ").id }})
if %found{name} && !%validator{name}.validate({{name.id.stringify}}, @{{name}})
@_validation_errors[{{name.stringify}}] ||= [] of String
@_validation_errors[{{name.stringify}}] += %validator{name}.errors
on_validation_error({{name.stringify}}, @{{name}}, %validator{name}.errors)
end
{% end %}
@ -189,7 +187,8 @@ module ArgParser
#
# Note: You can override this method to change the way validation errors are handled.
def on_validation_error(key : String, value, errors : Array(String))
raise ValidationError.new(key, errors)
add_validation_error(key, erorrs)
raise ValidationError.new(key, value, errors)
end
# Called when a value cannot be converted to the expected type.
@ -199,6 +198,11 @@ module ArgParser
raise ConversionError.new(key, value, type)
end
def add_validation_error(key : String, value, errors : Array(String))
@errors[key] ||= [] of String
@errors[key].concat errors
end
# https://en.wikipedia.org/wiki/Quotation_mark#Summary_table
QUOTE_CHARS = {'"' => '"', '“' => '”', '' => '', '«' => '»', '' => '', '❛' => '❜', '❝' => '❞', '' => '', '' => ''}

View File

@ -1,5 +1,5 @@
module ArgParser::EnumValueConverter(E)
def self.from_arg(arg)
E.new(arg)
E.from_value(arg.to_i64)
end
end

View File

@ -1,5 +1,5 @@
module ArgParser::EpochConverter
def self.from_arg(arg)
Time.epoch(arg.to_i64)
Time.unix(arg.to_i64)
end
end

View File

@ -1,5 +1,5 @@
module ArgParser::EpochMillisConverter
def self.from_arg(arg)
Time.epoch_ms(arg.to_i64)
Time.unix_ms(arg.to_i64)
end
end

View File

@ -18,8 +18,9 @@ module ArgParser
end
class ValidationError < Error
def initialize(name, errors)
super("Validation failed for #{name}: #{errors.join(", ")}")
def initialize(name, value, errors)
super("Validation failed for field :#{name} with value #{value.inspect}:\n" +
errors.map { |e| " - #{e}" }.join("\n"))
end
end