aboutsummaryrefslogtreecommitdiff
path: root/spec/practical
diff options
context:
space:
mode:
Diffstat (limited to 'spec/practical')
-rw-r--r--spec/practical/json_spec.cr118
1 files changed, 106 insertions, 12 deletions
diff --git a/spec/practical/json_spec.cr b/spec/practical/json_spec.cr
index 95795e2..43455da 100644
--- a/spec/practical/json_spec.cr
+++ b/spec/practical/json_spec.cr
@@ -30,12 +30,45 @@ def json_bool
end
# Only standard decimal ints for now
+#def json_number
+# base_num = Parser(Char, Char).satisfy(&.ascii_number?).some.map do |cs|
+# cs.join.to_i64
+# end
+# sign = Parser.token('-').map_const(-1).recover(1)
+# (sign + base_num).map { |s, n| JSONValue.new(s.to_i64 * n) }
+#end
+
def json_number
- base_num = Parser(Char, Char).satisfy(&.ascii_number?).some.map do |cs|
- cs.join.to_i64
- end
+ digits = Parser(Char, Char).satisfy(&.ascii_number?).many
sign = Parser.token('-').map_const(-1).recover(1)
- (sign + base_num).map { |s, n| JSONValue.new(s.to_i64 * n) }
+ point = Parser.token('.').optional
+
+ sign.and_then do |s|
+ digits.and_then do |front|
+ point.and_then do |p|
+ digits.and_then do |back|
+ if front.empty? && back.empty?
+ Parser(Char, JSONValue).flunk
+ else
+ x =
+ case
+ when front.empty? && !p.nil? # {[], '.', _} # 0 <= x < 1
+ "0.#{back.join}".to_f64
+ when back.empty? #{_, _, []} # whole number
+ front.join.to_i64
+ else #when !front.empty? && !p.nil? && !back.empty? # some other float
+ "#{front.join}.#{back.join}".to_f64
+ #else
+ # raise "json_number, Should be unreachable: #{front} #{p} #{back}"
+ end
+
+ x = x.to_i64 if x.is_a?(Float64) && (x % 1).zero?
+ Parser(Char, JSONValue).pure(JSONValue.new(x * s))
+ end
+ end
+ end
+ end
+ end
end
def json_value : Parser(Char, JSONValue)
@@ -72,15 +105,62 @@ describe "example: JSON parsing" do
end
describe "json_number" do
- it "parses strings of digits and other key characters and converts to number" do
- result = json_number.parse(Tokens.from_string("42"))
- result.value.data.should eq(42)
- result.tokens.empty?.should be_true
+ it "parses positive and negative integers" do
+ {"42", "42.", "42.000000"}.each do |s|
+ result = json_number.parse(Tokens.from_string(s))
+ result.value.data.should eq(42)
+ result.value.data.should be_a(Int64)
+ result.tokens.empty?.should be_true
+
+ result = json_number.parse(Tokens.from_string("-#{s}"))
+ result.value.data.should eq(-42)
+ result.value.data.should be_a(Int64)
+ result.tokens.empty?.should be_true
+ end
+ end
- result = json_number.parse(Tokens.from_string("-42"))
- result.value.data.should eq(-42)
- result.tokens.empty?.should be_true
+ it "parses positive and negative floats between -1 and 1" do
+ {"0.1234", ".1234", ".12340000"}.each do |s|
+ result = json_number.parse(Tokens.from_string(s))
+ result.value.data.should eq(0.1234)
+ result.value.data.should be_a(Float64)
+ result.tokens.empty?.should be_true
+
+ result = json_number.parse(Tokens.from_string("-#{s}"))
+ result.value.data.should eq(-0.1234)
+ result.value.data.should be_a(Float64)
+ result.tokens.empty?.should be_true
+ end
+ end
+ it "parses positive and negative floats with a whole-number component" do
+ {"12.34", "0012.3400"}.each do |s|
+ result = json_number.parse(Tokens.from_string(s))
+ result.value.data.should eq(12.34)
+ result.value.data.should be_a(Float64)
+ result.tokens.empty?.should be_true
+
+ result = json_number.parse(Tokens.from_string("-#{s}"))
+ result.value.data.should eq(-12.34)
+ result.value.data.should be_a(Float64)
+ result.tokens.empty?.should be_true
+ end
+ end
+
+ it "parses 0 as an int in various forms" do
+ {"0", "0.0", "0000", ".000", "000.", "-0", "-0.", "-.0", "-0.0"}.each do |s|
+ result = json_number.parse(Tokens.from_string(s))
+ result.value.data.should eq(0)
+ result.value.data.should be_a(Int64)
+ result.tokens.empty?.should be_true
+ end
+ end
+
+ it "does not parse '.' or '-.' as 0" do
+ expect_raises(ParserFail) { json_number.parse(Tokens.from_string(".")) }
+ end
+
+ it "fails when input if not a number" do
expect_raises(ParserFail) { json_number.parse(Tokens.from_string("")) }
expect_raises(ParserFail) { json_number.parse(Tokens.from_string("foo")) }
end
@@ -103,13 +183,27 @@ describe "example: JSON parsing" do
result.tokens.empty?.should be_true
end
- it "parsers ints" do
+ it "parses ints" do
result = json_value.parse(Tokens.from_string("42"))
result.value.data.should eq(42)
+ result.value.data.should be_a(Int64)
result.tokens.empty?.should be_true
result = json_value.parse(Tokens.from_string("-42"))
result.value.data.should eq(-42)
+ result.value.data.should be_a(Int64)
+ result.tokens.empty?.should be_true
+ end
+
+ it "parses floats" do
+ result = json_value.parse(Tokens.from_string("12.34"))
+ result.value.data.should eq(12.34)
+ result.value.data.should be_a(Float64)
+ result.tokens.empty?.should be_true
+
+ result = json_value.parse(Tokens.from_string("-12.34"))
+ result.value.data.should eq(-12.34)
+ result.value.data.should be_a(Float64)
result.tokens.empty?.should be_true
end
end