require "./spec_helper" require "../src/parcom.cr" include Parcom describe Result do describe "#initialize" do it "sets values for #tokens and #value" do tokens = "esting".chars value = 't' result = Result(Char, Char).new(tokens, value) result.tokens.should eq(tokens) result.value.should eq(value) end end end describe Parser do describe "#parse?" do it "returns `nil` if the parser fails" do result = AnyToken(Char).new.parse?([] of Char) result.should be_nil end it "returns a `Result(T, V)` if the parser succeeds" do tokens = "testing".chars result = AnyToken(Char).new.parse(tokens) result.should be_a(Result(Char, Char)) end end describe "#|" do it "creates an `Alt` instance from `self` and another `Parser(T, V)`" do p = AnyToken(Char).new | AnyToken(Char).new p.should be_a(Alt(Char, Char)) end end describe "#assert" do it "creates an `Assert` instance from `self` and a `Proc(T, Bool)`" do f = ->(x : Char) { x == '#' } p = AnyToken(Char).new.assert(f) p.should be_a(Assert(Char, Char)) end end describe "#map" do it "creates a `Map(T, V, U)` instance from `self` and a Proc(V, U)" do f = ->(x : Char) { x.letter? } p = AnyToken(Char).new.map(f) p.should be_a(Map(Char, Char, Bool)) end end end describe Flunk do describe "#parse" do it "always fails" do tokens = "testing".chars expect_raises(ParserException) { Flunk(Char, Char).new.parse(tokens) } end end end describe AnyToken do describe "#parse" do it "succeeds when input is non-empty" do tokens = "testing".chars result = AnyToken(Char).new.parse(tokens) result.tokens.should eq(tokens[1..]) result.value.should eq('t') end it "fails when input is empty" do p = AnyToken(Char).new expect_raises(ParserException) { p.parse([] of Char) } end end end describe Eof do describe "#parse" do it "succeeds when input is empty" do result = Eof(Char).new.parse([] of Char) result.tokens.empty?.should be_true result.value.should be_nil end it "fails when input is non-empty" do tokens = "testing".chars expect_raises(ParserException) { Eof(Char).new.parse(tokens) } end end end describe Peek do describe "#parse" do it "does not modify the result of the wrapped parser" do tokens = "testing".chars parser = AnyToken(Char).new result_normal = parser.parse(tokens) result_peek = Peek.new(parser).parse(tokens) result_peek.value.should eq(result_normal.value) end it "does not consume any input" do tokens = "testing".chars parser = AnyToken(Char).new result = Peek.new(parser).parse(tokens) result.tokens.should eq(tokens) end end end describe Assert do describe "#parse" do it "fails if the wrapped parser fails" do test = ->(x : Char) { true } # doesn't matter for this test p = Assert.new(AnyToken(Char).new, test) expect_raises(ParserException) { p.parse([] of Char) } end it "fails if the result value fails the test" do tokens = "testing".chars test = ->(x : Char) { x == '$' } p = Assert.new(AnyToken(Char).new, test) expect_raises(ParserException) { p.parse(tokens) } end it "succeeds if the wrapped parser succeeds and the test passes" do tokens = "testing".chars expected_char = tokens[0] test = ->(x : Char) { x == expected_char } p = Assert.new(AnyToken(Char).new, test) result = p.parse(tokens) result.value.should eq(expected_char) test.call(expected_char).should be_true end end end describe Satisfy do describe "#parse" do it "fails if there are input is empty" do test = ->(x : Char) { x == '#' } # doesn't matter for this case p = Satisfy(Char).new(test) expect_raises(ParserException) { p.parse([] of Char) } end it "fails if the token fails the test" do tokens = "testing".chars test = ->(x : Char) { x == '#' } p = Satisfy(Char).new(test) expect_raises(ParserException) { p.parse(tokens) } end it "succeeds if the token passes the test" do tokens = "testing".chars expected_char = tokens[0] test = ->(x : Char) { x == expected_char } p = Satisfy(Char).new(test) result = p.parse(tokens) result.value.should eq(expected_char) test.call(result.value).should be_true end end end describe Token do describe "#parse" do it "fails if the input is empty" do p = Token(Char).new('t') expect_raises(ParserException) { p.parse([] of Char) } end it "fails if the token is not the expected token" do tokens = "testing".chars p = Token(Char).new('#') expect_raises(ParserException) { p.parse(tokens) } end it "succeeds if the token is the expected token" do tokens = "testing".chars expected_char = tokens[0] p = Token(Char).new(expected_char) result = p.parse(tokens) result.value.should eq(expected_char) end end end describe Map do describe "#parse" do it "fails if the wrapped parser fails" do id = ->(x : Char) { x } p = Map.new(AnyToken(Char).new, id) expect_raises(ParserException) { p.parse([] of Char) } end it "changes the result value via the provided proc" do is_letter = ->(x : Char) { x.letter? } p = Map.new(AnyToken(Char).new, is_letter) result = p.parse("testing".chars) result.value.should be_true result = p.parse("_testing".chars) result.value.should be_false end end end pending Phrase do end pending Plus do end pending Recover do end pending Optional do end pending Tokens do end pending Many do end pending Some do end pending Exactly do end pending AtLeast do end pending AtMost do end pending Between do end pending StopAt do end pending StopAfter do end pending StopIf do end pending FirstOf do end pending SepBy do end