Skip to content

Commit

Permalink
from_yaml & to_yaml hardening + specs
Browse files Browse the repository at this point in the history
  • Loading branch information
jwaldrip committed Aug 19, 2017
1 parent ade6b05 commit 93b5de0
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 24 deletions.
387 changes: 387 additions & 0 deletions spec/std/yaml/from_yaml_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
require "spec"
require "yaml"

private class ObjectStub
def self.new(pp : YAML::PullParser)
pp.read_scalar.should eq "hello"
new
end
end

describe "Object.from_yaml" do
it "should create call .new on with a YAML::PullParser" do
ObjectStub.from_yaml("hello")
end
end

describe "Nil.from_yaml" do
YAML::NullValues.each do |value|
it "should serialize and deserialize" do
Nil.from_yaml(nil.to_yaml).should eq nil
end

it "should return nil if #{value}" do
# Test will an array since a standalone empty value shows as STREAM_END
Array(Nil).from_yaml("- " + value).should eq [nil]
end

it "should raise if #{value} is quoted with double quotes" do
expect_raises(YAML::ParseException) do
Nil.from_yaml "\"#{value}\""
end
end

it "should raise if #{value} is quoted with single quotes" do
expect_raises(YAML::ParseException) do
Nil.from_yaml "'#{value}'"
end
end
end

it "should raise if not a null value" do
expect_raises(YAML::ParseException) do
Nil.from_yaml "hello"
end
end
end

describe "Bool.from_yaml" do

describe "true values" do
it "should serialize and deserialize" do
Bool.from_yaml(true.to_yaml).should eq true
end

YAML::BoolTrueValues.each do |value|
it "should return true if #{value}" do
Bool.from_yaml(value).should eq true
end

it "should raise if #{value} is quoted with double quotes" do
expect_raises(YAML::ParseException) do
Bool.from_yaml "\"#{value}\""
end
end

it "should raise if #{value} is quoted with single quotes" do
expect_raises(YAML::ParseException) do
Bool.from_yaml "'#{value}'"
end
end
end
end

describe "false values" do
it "should serialize and deserialize" do
Bool.from_yaml(false.to_yaml).should eq false
end

YAML::BoolFalseValues.each do |value|
it "should return true if #{value}" do
Bool.from_yaml(value).should eq false
end

it "should raise if #{value} is quoted with double quotes" do
expect_raises(YAML::ParseException) do
Bool.from_yaml "\"#{value}\""
end
end

it "should raise if #{value} is quoted with single quotes" do
expect_raises(YAML::ParseException) do
Bool.from_yaml "'#{value}'"
end
end
end
end

it "should raise if not a bool value" do
expect_raises(YAML::ParseException) do
Bool.from_yaml "hello"
end
end
end


{% for type in %w(Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64) %}
describe "{{type.id}}.from_yaml" do
it "should serialize and deserialize" do
{{type.id}}.from_yaml({{type.id}}.new("1").to_yaml).should eq {{type.id}}.new("1")
end

it "should parse a number into an {{type.id}}" do
{{type.id}}.from_yaml("1").should eq {{type.id}}.new("1")
end

it "should raise if quoted with double quotes" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml "\"1\""
end
end

it "should raise if quoted with single quotes" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml "'1'"
end
end

it "should raise when not a number" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml("hi")
end
end
end
{% end %}

{% for type in %w(Float32 Float64) %}
describe "{{type.id}}.from_yaml" do
it "should serialize and deserialize" do
{{type.id}}.from_yaml({{type.id}}.new("1.0").to_yaml).should eq {{type.id}}.new("1.0")
end

it "should parse a number into an {{type.id}}" do
{{type.id}}.from_yaml("1").should eq {{type.id}}.new("1")
end

it "should parse a float into an {{type.id}}" do
{{type.id}}.from_yaml("1.1").should eq {{type.id}}.new("1.1")
end

it "should raise if quoted with double quotes" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml "\"1.1\""
end
end

it "should raise if quoted with single quotes" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml "'1.1'"
end
end

it "should raise when not a float or number" do
expect_raises(YAML::ParseException) do
{{type.id}}.from_yaml("hi")
end
end
end
{% end %}

describe "String.from_yaml" do
it "should serialize and deserialize" do
String.from_yaml("hi".to_yaml).should eq "hi"
end

it "should parse a string" do
String.from_yaml("hello").should eq "hello"
end

it "should parse a single quoted string" do
String.from_yaml("'hello'").should eq "hello"
end

it "should parse a double quoted string" do
String.from_yaml("\"hello\"").should eq "hello"
end

it "should parse a literal string" do
String.from_yaml("|\n hello").should eq "hello"
end

it "should parse a folded string" do
String.from_yaml(">\n hello").should eq "hello"
end

context "bool values" do
YAML::BoolValues.each do |value|
it "should raise if #{value}" do
expect_raises(YAML::ParseException) do
String.from_yaml(value)
end
end

it "should parse if #{value} is quoted with double quotes" do
String.from_yaml("\"#{value}\"").should eq value
end

it "should parse if #{value} is quoted with single quotes" do
String.from_yaml("'#{value}'").should eq value
end
end
end

context "nil values" do
YAML::NullValues.each do |value|
it "should raise if #{value}" do
expect_raises(YAML::ParseException) do
# Test will an array since a standalone empty value shows as STREAM_END
Array(String).from_yaml("- " + value)
end
end

it "should parse if #{value} is quoted with double quotes" do
String.from_yaml("\"#{value}\"").should eq value
end

it "should parse if #{value} is quoted with single quotes" do
String.from_yaml("'#{value}'").should eq value
end
end
end

context "integers" do
it "should raise if an int is passed" do
expect_raises(YAML::ParseException) do
String.from_yaml("1")
end

it "should parse if the int is quoted with double quotes" do
String.from_yaml("\"1\"").should eq "1"
end

it "should parse if the int is quoted with single quotes" do
String.from_yaml("'1'").should eq "1"
end
end
end

context "floats" do
it "should raise if an int is passed" do
expect_raises(YAML::ParseException) do
String.from_yaml("1.1")
end

it "should parse if the int is quoted with double quotes" do
String.from_yaml("\"1.1\"").should eq "1.1"
end

it "should parse if the int is quoted with single quotes" do
String.from_yaml("'1.1'").should eq "1.1"
end
end
end
end

describe "Array.from_yaml" do
it "should serialize and deserialize" do
Array(String).from_yaml(["hi"].to_yaml).should eq ["hi"]
end

it "it should an array of the correct objects" do
result = Array(String).from_yaml <<-YAML
- one
- two
- three
YAML
result.should eq ["one", "two", "three"]
end

context "with a union type" do
it "it should an array of the correct objects" do
result = Array(String | Int32 | Float64).from_yaml <<-YAML
- one
- 1
- 1.0
YAML
result.should eq ["one", 1, 1.0]
end
end
end

describe "Hash.from_yaml" do
it "should serialize and deserialize" do
Hash(String, String).from_yaml({"hello" => "world" }.to_yaml).should eq ({ "hello" => "world" })
end

it "it should an array of the correct objects" do
result = Hash(String, String).from_yaml <<-YAML
foo: one
bar: two
baz: three
YAML
result.should eq ({ "foo" => "one", "bar" => "two", "baz" => "three" })
end

context "with a union type" do
it "it should an array of the correct objects" do
result = Hash(String, String | Int32 | Float64).from_yaml <<-YAML
foo: 1
bar: two
baz: 3.0
YAML
result.should eq ({ "foo" => 1, "bar" => "two", "baz" => 3.0 })
end
end
end

describe "Tuple.from_yaml" do
it "should serialize and deserialize" do
Tuple(String, String).from_yaml({"hello", "world" }.to_yaml).should eq ({ "hello", "world" })
end

it "it should an array of the correct objects" do
result = Tuple(String, String, String).from_yaml "- one\n- two\n- three"
result.should eq ({ "one", "two", "three" })
end

context "with a union type" do
it "it should an array of the correct objects" do
result = Tuple(String | Int32 | Float64, String | Int32 | Float64, String | Int32 | Float64).from_yaml "- one\n- 1\n- 1.0"
result.should eq ({"one", 1, 1.0})
end
end
end

describe "NamedTuple.from_yaml" do
it "it should an array of the correct objects" do
result = NamedTuple(foo: String, bar: String, baz: String).from_yaml "foo: one\nbar: two\nbaz: three"
result.should eq ({ foo: "one", bar: "two", baz: "three" })
end
end

enum TestEnum
Red
Green
Blue
end

describe "Enum.from_yaml" do
it "should serialize and deserialize" do
TestEnum.from_yaml(TestEnum::Red.to_yaml).should eq TestEnum::Red
end

it "should parse from string" do
TestEnum.from_yaml("red").should eq TestEnum::Red
end

it "should parse from int" do
TestEnum.from_yaml("1").should eq TestEnum::Green
end
end

describe "Union.from_yaml" do
it "should compile into any of the types" do
(Bool | Int32).from_yaml("true").should eq true
(Bool | Int32).from_yaml("1").should eq 1
end

it "should raise if not a unions type" do
expect_raises(YAML::ParseException) do
(Bool | Int32).from_yaml("foo")
end
end
end

describe "Time.from_yaml" do
it "should parse time" do
time = Time.now
time_string = Time::Format::ISO_8601_DATE_TIME.format(time)
Time.from_yaml(time_string).epoch.should eq time.epoch
end

it "should not parse an invalid time string" do
expect_raises(YAML::ParseException) do
Time.from_yaml("not a time")
end
end
end
10 changes: 10 additions & 0 deletions spec/std/yaml/to_yaml_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "spec"
require "yaml"

describe "String.to_yaml" do
YAML::StringQuotedValues.each do |value|
it "should quote non-string scalars" do
[value].to_yaml.should eq "---\n- \"#{value}\"\n"
end
end
end
Loading

0 comments on commit 93b5de0

Please sign in to comment.