spec/parsers/number_parser_spec.rb (150 lines of code) (raw):
# encoding: UTF-8
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
require 'spec_helper'
describe TwitterCldr::Parsers::NumberParser do
let(:separators) { ["\\.", ","] }
before(:each) do
@parser = described_class.new(:es)
end
describe "#group_separator" do
it "returns the correct group separator" do
expect(@parser.send(:group_separator)).to match_normalized("\\.")
end
end
describe "#decimal_separator" do
it "returns the correct decimal separator" do
expect(@parser.send(:decimal_separator)).to eq(",")
end
end
describe "#identify" do
it "properly identifies a numeric value" do
expect(@parser.send(:identify, "7841", *separators)).to eq({ value: "7841", type: :numeric })
end
it "properly identifies a decimal separator" do
expect(@parser.send(:identify, ",", *separators)).to eq({ value: ",", type: :decimal })
end
it "properly identifies a group separator" do
expect(@parser.send(:identify, ".", *separators)).to eq({ value: ".", type: :group })
end
it "returns nil if the text doesn't match a number or either separators" do
expect(@parser.send(:identify, "abc", *separators)).to eq({ value: "abc", type: nil })
end
end
describe "#tokenize" do
it "splits text by numericality and group/decimal separators" do
expect(@parser.send(:tokenize, "1,33.00", *separators)).to eq([
{ value: "1", type: :numeric },
{ value: ",", type: :decimal },
{ value: "33", type: :numeric },
{ value: ".", type: :group },
{ value: "00", type: :numeric }
])
end
it "returns an empty array for a non-numeric string" do
expect(@parser.send(:tokenize, "abc", *separators)).to be_empty
end
end
describe "#separators" do
it "returns all separators when strict mode is off" do
group, decimal = @parser.send(:separators, false)
expect(group).to eq('\.,\s')
expect(decimal).to eq('\.,\s')
end
it "returns only locale-specific separators when strict mode is on" do
group, decimal = @parser.send(:separators, true)
expect(group).to match_normalized("\\.")
expect(decimal).to eq(',')
end
end
describe "#punct_valid" do
it "correctly validates a number with no decimal" do
tokens = @parser.send(:tokenize, "1.337", *separators).reject { |t| t[:type] == :numeric }
expect(@parser.send(:punct_valid?, tokens)).to eq(true)
end
it "correctly validates a number with a decimal" do
tokens = @parser.send(:tokenize, "1.337,00", *separators).reject { |t| t[:type] == :numeric }
expect(@parser.send(:punct_valid?, tokens)).to eq(true)
end
it "reports on an invalid number when it has more than one decimal" do
tokens = @parser.send(:tokenize, "1,337,00", *separators).reject { |t| t[:type] == :numeric }
expect(@parser.send(:punct_valid?, tokens)).to eq(false)
end
end
describe "#is_numeric?" do
it "returns true if the text is numeric" do
expect(described_class.is_numeric?("4839", "")).to eq(true)
expect(described_class.is_numeric?("1", "")).to eq(true)
end
it "returns false if the text is not purely numeric" do
expect(described_class.is_numeric?("abc", "")).to eq(false)
expect(described_class.is_numeric?("123abc", "")).to eq(false)
end
it "returns false if the text is blank" do
expect(described_class.is_numeric?("", "")).to eq(false)
end
it "accepts the given characters as valid numerics" do
expect(described_class.is_numeric?("a123a", "a")).to eq(true)
expect(described_class.is_numeric?("1.234,56")).to eq(true) # default separator chars used here
end
end
describe "#valid?" do
it "correctly identifies a series of valid cases" do
["5", "5,0", "1.337", "1.337,0", "0,05", ",5", "1.337.000,00"].each do |num|
expect(@parser.valid?(num)).to eq(true)
end
end
it "correctly identifies a series of invalid cases" do
["12,0,0", "5,", "5."].each do |num|
expect(@parser.valid?(num)).to eq(false)
end
end
end
describe "#parse" do
it "correctly parses a series of valid numbers" do
cases = {
"5" => 5,
"5,0" => 5.0,
"1.337" => 1337,
"1.337,0" => 1337.0,
"0,05" => 0.05,
",5" => 0.5,
"1.337.000,00" => 1337000.0
}
cases.each do |text, expected|
expect(@parser.parse(text)).to eq(expected)
end
end
it "correctly raises an error when asked to parse invalid numbers" do
cases = ["12,0,0", "5,", "5."]
cases.each do |text|
expect { @parser.parse(text) }.to raise_error(TwitterCldr::Parsers::InvalidNumberError)
end
end
context "non-strict" do
it "succeeds in parsing even if inexact punctuation is used" do
expect(@parser.parse("5 100", strict: false)).to eq(5100)
end
end
end
describe "#try_parse" do
it "parses correctly with a valid number" do
expect(@parser.try_parse("1.234")).to eq(1234)
end
it "parses correctly with a valid number and yields to the given block" do
pre_result = nil
expect(@parser.try_parse("1.234") do |result|
pre_result = result
9
end).to eq(9)
expect(pre_result).to eq(1234)
end
it "falls back on the default value if the number is invalid" do
expect(@parser.try_parse("5,")).to be_nil
expect(@parser.try_parse("5,", 0)).to eq(0)
end
it "falls back on the block if the number is invalid" do
expect(@parser.try_parse("5,") { |result| 9 }).to eq(9)
end
it "doesn't catch anything but an InvalidNumberError" do
expect { @parser.try_parse(Object.new) }.to raise_error(NoMethodError)
end
end
end