Skip to content

Commit

Permalink
Add URI::Params::Serializable (#14684)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blacksmoke16 authored Aug 23, 2024
1 parent cc6859b commit cc0dfc1
Show file tree
Hide file tree
Showing 7 changed files with 589 additions and 0 deletions.
151 changes: 151 additions & 0 deletions spec/std/uri/params/from_www_form_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
require "spec"
require "uri/params/serializable"

private enum Color
Red
Green
Blue
end

describe ".from_www_form" do
it Array do
Array(Int32).from_www_form(URI::Params.new({"values" => ["1", "2"]}), "values").should eq [1, 2]
Array(Int32).from_www_form(URI::Params.new({"values[]" => ["1", "2"]}), "values").should eq [1, 2]
Array(String).from_www_form(URI::Params.new({"values" => ["", ""]}), "values").should eq ["", ""]
end

describe Bool do
it "a truthy value" do
Bool.from_www_form("true").should be_true
Bool.from_www_form("on").should be_true
Bool.from_www_form("yes").should be_true
Bool.from_www_form("1").should be_true
end

it "a falsey value" do
Bool.from_www_form("false").should be_false
Bool.from_www_form("off").should be_false
Bool.from_www_form("no").should be_false
Bool.from_www_form("0").should be_false
end

it "any other value" do
Bool.from_www_form("foo").should be_nil
Bool.from_www_form("").should be_nil
end
end

describe String do
it "scalar string" do
String.from_www_form("John Doe").should eq "John Doe"
end

it "with key" do
String.from_www_form(URI::Params.new({"name" => ["John Doe"]}), "name").should eq "John Doe"
end

it "with missing key" do
String.from_www_form(URI::Params.new({"" => ["John Doe"]}), "name").should be_nil
end

it "with alternate casing" do
String.from_www_form(URI::Params.new({"Name" => ["John Doe"]}), "name").should be_nil
end

it "empty value" do
String.from_www_form(URI::Params.new({"name" => [""]}), "name").should eq ""
end
end

describe Enum do
it "valid value" do
Color.from_www_form("green").should eq Color::Green
end

it "invalid value" do
expect_raises ArgumentError do
Color.from_www_form ""
end
end
end

describe Time do
it "valid value" do
Time.from_www_form("2016-11-16T09:55:48-03:00").to_utc.should eq(Time.utc(2016, 11, 16, 12, 55, 48))
Time.from_www_form("2016-11-16T09:55:48-0300").to_utc.should eq(Time.utc(2016, 11, 16, 12, 55, 48))
Time.from_www_form("20161116T095548-03:00").to_utc.should eq(Time.utc(2016, 11, 16, 12, 55, 48))
end

it "invalid value" do
expect_raises Time::Format::Error do
Time.from_www_form ""
end
end
end

describe Nil do
it "valid values" do
Nil.from_www_form("").should be_nil
end

it "invalid value" do
expect_raises ArgumentError do
Nil.from_www_form "null"
end
end
end

describe Number do
describe Int do
it "valid numbers" do
Int64.from_www_form("123").should eq 123_i64
UInt8.from_www_form("7").should eq 7_u8
Int64.from_www_form("-12").should eq -12_i64
end

it "with whitespace" do
expect_raises ArgumentError do
Int32.from_www_form(" 123")
end
end

it "empty value" do
expect_raises ArgumentError do
Int16.from_www_form ""
end
end
end

describe Float do
it "valid numbers" do
Float32.from_www_form("123.0").should eq 123_f32
Float64.from_www_form("123.0").should eq 123_f64
end

it "with whitespace" do
expect_raises ArgumentError do
Float64.from_www_form(" 123.0")
end
end

it "empty value" do
expect_raises Exception do
Float64.from_www_form ""
end
end
end
end

describe Union do
it "valid" do
String?.from_www_form(URI::Params.parse("name=John Doe"), "name").should eq "John Doe"
String?.from_www_form(URI::Params.parse("name="), "name").should eq ""
end

it "invalid" do
expect_raises ArgumentError do
(Int32 | Float64).from_www_form(URI::Params.parse("name=John Doe"), "name")
end
end
end
end
133 changes: 133 additions & 0 deletions spec/std/uri/params/serializable_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
require "spec"
require "uri/params/serializable"

private record SimpleType, page : Int32, strict : Bool, per_page : UInt8 do
include URI::Params::Serializable
end

private record SimpleTypeDefaults, page : Int32, strict : Bool, per_page : Int32 = 10 do
include URI::Params::Serializable
end

private record SimpleTypeNilable, page : Int32, strict : Bool, per_page : Int32? = nil do
include URI::Params::Serializable
end

private record SimpleTypeNilableDefault, page : Int32, strict : Bool, per_page : Int32? = 20 do
include URI::Params::Serializable
end

record Filter, status : String?, total : Float64? do
include URI::Params::Serializable
end

record Search, filter : Filter?, limit : Int32 = 25, offset : Int32 = 0 do
include URI::Params::Serializable
end

record GrandChild, name : String do
include URI::Params::Serializable
end

record Child, status : String?, grand_child : GrandChild do
include URI::Params::Serializable
end

record Parent, child : Child do
include URI::Params::Serializable
end

module MyConverter
def self.from_www_form(params : URI::Params, name : String)
params[name].to_i * 10
end
end

private record ConverterType, value : Int32 do
include URI::Params::Serializable

@[URI::Params::Field(converter: MyConverter)]
@value : Int32
end

class ParentType
include URI::Params::Serializable

getter name : String
end

class ChildType < ParentType
end

describe URI::Params::Serializable do
describe ".from_www_form" do
it "simple type" do
SimpleType.from_www_form("page=10&strict=true&per_page=5").should eq SimpleType.new(10, true, 5)
end

it "missing required property" do
expect_raises URI::SerializableError, "Missing required property: 'page'." do
SimpleType.from_www_form("strict=true&per_page=5")
end
end

it "with default values" do
SimpleTypeDefaults.from_www_form("page=10&strict=off").should eq SimpleTypeDefaults.new(10, false, 10)
end

it "with nilable values" do
SimpleTypeNilable.from_www_form("page=10&strict=true").should eq SimpleTypeNilable.new(10, true, nil)
end

it "with nilable default" do
SimpleTypeNilableDefault.from_www_form("page=10&strict=true").should eq SimpleTypeNilableDefault.new(10, true, 20)
end

it "with custom converter" do
ConverterType.from_www_form("value=10").should eq ConverterType.new(100)
end

it "child type" do
ChildType.from_www_form("name=Fred").name.should eq "Fred"
end

describe "nested type" do
it "happy path" do
Search.from_www_form("offset=10&filter[status]=active&filter[total]=3.14")
.should eq Search.new Filter.new("active", 3.14), offset: 10
end

it "missing nilable nested data" do
Search.from_www_form("offset=10")
.should eq Search.new Filter.new(nil, nil), offset: 10
end

it "missing required nested property" do
expect_raises URI::SerializableError, "Missing required property: 'child[grand_child][name]'." do
Parent.from_www_form("child[status]=active")
end
end

it "doubly nested" do
Parent.from_www_form("child[status]=active&child[grand_child][name]=Fred")
.should eq Parent.new Child.new("active", GrandChild.new("Fred"))
end
end
end

describe "#to_www_form" do
it "simple type" do
SimpleType.new(10, true, 5).to_www_form.should eq "page=10&strict=true&per_page=5"
end

it "nested type path" do
Search.new(Filter.new("active", 3.14), offset: 10).to_www_form
.should eq "filter%5Bstatus%5D=active&filter%5Btotal%5D=3.14&limit=25&offset=10"
end

it "doubly nested" do
Parent.new(Child.new("active", GrandChild.new("Fred"))).to_www_form
.should eq "child%5Bstatus%5D=active&child%5Bgrand_child%5D%5Bname%5D=Fred"
end
end
end
60 changes: 60 additions & 0 deletions spec/std/uri/params/to_www_form_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require "spec"
require "uri/params/serializable"

private enum Color
Red
Green
BlueGreen
end

describe "#to_www_form" do
it Number do
URI::Params.build do |builder|
12.to_www_form builder, "value"
end.should eq "value=12"
end

it Enum do
URI::Params.build do |builder|
Color::BlueGreen.to_www_form builder, "value"
end.should eq "value=blue_green"
end

it String do
URI::Params.build do |builder|
"12".to_www_form builder, "value"
end.should eq "value=12"
end

it Bool do
URI::Params.build do |builder|
false.to_www_form builder, "value"
end.should eq "value=false"
end

it Nil do
URI::Params.build do |builder|
nil.to_www_form builder, "value"
end.should eq "value="
end

it Time do
URI::Params.build do |builder|
Time.utc(2024, 8, 6, 9, 48, 10).to_www_form builder, "value"
end.should eq "value=2024-08-06T09%3A48%3A10Z"
end

describe Array do
it "of a single type" do
URI::Params.build do |builder|
[1, 2, 3].to_www_form builder, "value"
end.should eq "value=1&value=2&value=3"
end

it "of a union of types" do
URI::Params.build do |builder|
[1, false, "foo"].to_www_form builder, "value"
end.should eq "value=1&value=false&value=foo"
end
end
end
1 change: 1 addition & 0 deletions src/docs_main.cr
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require "./string_pool"
require "./string_scanner"
require "./unicode/unicode"
require "./uri"
require "./uri/params/serializable"
require "./uuid"
require "./uuid/json"
require "./syscall"
Expand Down
Loading

0 comments on commit cc0dfc1

Please sign in to comment.