//================================================================================ func TestStateStack(t *testing.T) { ts.LogAsserts("StateStack", t, func(tt *ts.T) { p0 := Bind(PushStateStack(555), func(c1 interface{}) Parser { return Bind(PushStateStack(556), func(c2 interface{}) Parser { return PushStateStack(557) }) }) p2 := SeqRight( SeqRight(p0, Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return PopStateStack() } else { return Return(nil) } })), GetState) tt.AssertEqual(parseStr(p2, "\naa"), PState{input: "aa", pos: 1, value: []interface{}{555, 556}, ok: true, user: []interface{}{555, 556}}) tt.AssertEqual(parseStr(p2, "abba"), PState{input: "bba", pos: 1, value: []interface{}{555, 556, 557}, ok: true, user: []interface{}{555, 556, 557}}) p3 := SeqRight(p0, Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return AlterTopStateStack(777) } else { return PeekStateStack() } })) tt.AssertEqual(parseStr(p3, "\nbc"), PState{input: "bc", pos: 1, ok: true, user: []interface{}{555, 556, 777}}) tt.AssertEqual(parseStr(p3, "abc"), PState{input: "bc", pos: 1, value: 557, ok: true, user: []interface{}{555, 556, 557}}) p4 := Bind(AnyChar, func(x interface{}) (p Parser) { if u8.Sur(x.(u8.Codepoint)) == "\n" { return AlterTopStateStack(777) } else { return PeekStateStack() } }) tt.AssertEqual(parseStr(p4, "\naa"), PState{input: "aa", pos: 1, error: "AlterTopStateStack doesn't handle zero-sized stacks."}) tt.AssertEqual(parseStr(p4, "abc"), PState{input: "bc", pos: 1, ok: true}) }) }
//================================================================================ func TestState(t *testing.T) { ts.LogAsserts("State", t, func(tt *ts.T) { incrIfNewline := func(x interface{}) Parser { if x.(u8.Codepoint) == u8.Codepoint('\n') { return ModifyState(func(n interface{}, _ ...interface{}) interface{} { return n.(int) + 1 }) } else { return Return(nil) } } p2 := SeqRight(PutState(21), Bind(AnyChar, incrIfNewline)) tt.AssertEqual(parseStr(p2, "\naa"), PState{input: "aa", pos: 1, value: u8.Codepoint('\n'), ok: true, user: 22}) tt.AssertEqual(parseStr(p2, "aaa"), PState{input: "aa", pos: 1, value: nil, ok: true, user: 21}) tt.AssertEqual(parseStr(p2, "aa\naa\na"), PState{input: "a\naa\na", pos: 1, value: nil, ok: true, user: 21}) p1 := SeqRight(PutState(21), Bind(AnyChar, incrIfNewline), GetState) tt.AssertEqual(parseStr(p1, "\naa"), PState{input: "aa", pos: 1, value: 22, ok: true, user: 22}) tt.AssertEqual(parseStr(p1, "aaa"), PState{input: "aa", pos: 1, value: 21, ok: true, user: 21}) tt.AssertEqual(parseStr(p1, "aa\naa\na"), PState{input: "a\naa\na", pos: 1, value: 21, ok: true, user: 21}) p3 := SeqRight(PutState(21), Bind(AnyChar, incrIfNewline), AnyChar) tt.AssertEqual(parseStr(p3, "\naa"), PState{input: "a", pos: 2, value: u8.Codepoint('a'), ok: true, user: 22}) tt.AssertEqual(parseStr(p3, "aaa"), PState{input: "a", pos: 2, value: u8.Codepoint('a'), ok: true, user: 21}) tt.AssertEqual(parseStr(p3, "aa\naa\na"), PState{input: "\naa\na", pos: 2, value: u8.Codepoint('a'), ok: true, user: 21}) tt.AssertEqual(parseStr(p3, "a\naa\na"), PState{input: "aa\na", pos: 2, value: u8.Codepoint('\n'), ok: true, user: 21}) }) }
//================================================================================ func TestAssertSkeletons(t *testing.T) { ts.LogAsserts("AssertSkeletons", t, func(tt *ts.T) { tt.Assert(true) tt.AssertEqual(1, 1) tt.AssertEqualN('a', 'a', 123) //tt.PrintValue("abcdefg") tt.AssertPanic(func() { if true { panic("X") } }, "X") tt.AssertAnyPanic(func() { if true { panic("X") } }) }) }
//================================================================================ func TestInputAndPosition(t *testing.T) { ts.LogAsserts("InputAndPosition", t, func(tt *ts.T) { letter := Regexp(`\pL`) p1 := Flatten(letter, letter, letter) tt.AssertEqual(parseStr(SeqRight(SetInput(u8.Desur("Hi!")), GetInput), "abcdefg"), PState{input: "Hi!", pos: 0, value: u8.Desur("Hi!"), empty: true, ok: true}) tt.AssertEqual(parseStr(SeqRight(letter, GetInput), "abcdefg"), PState{input: "bcdefg", pos: 1, value: u8.Desur("bcdefg"), ok: true}) tt.AssertEqual(parseStr(SeqRight(SetPosition(100), GetPosition), "abcdefg"), PState{input: "abcdefg", pos: 100, value: uint64(100), empty: true, ok: true}) tt.AssertEqual(parseStr(SeqRight(SetInputAndPosition(InputAndPosition{u8.Desur("Hi there!"), 5}), GetInputAndPosition), "abcdefg"), PState{input: "Hi there!", pos: 5, value: InputAndPosition{u8.Desur("Hi there!"), 5}, empty: true, ok: true}) tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInput(u8.Desur("XYZ")), p1)), "ABCDEFG"), PState{input: "", pos: 6, value: arrText("ABC", "XYZ"), ok: true}) //TODO: what should pos be? tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInput(u8.Desur("XYZ")), p1)), "ABC"), PState{input: "", pos: 6, value: arrText("ABC", "XYZ"), ok: true}) //TODO: ditto tt.AssertEqual(parseStr(Collect(p1), "ABC"), PState{input: "", pos: 3, value: arrText("ABC"), ok: true}) p2 := SeqRight(Skip(SetInput(u8.Text("XY0")), SetPosition(0)), p1) tt.AssertEqual(parseStr(Collect(p1, p2), "ABC"), PState{input: "0", pos: 2, value: nil, error: makeUnexpInp("0")}) p3 := SeqRight(Skip(SetInput(u8.Text("WXYZ")), SetPosition(0)), GetPosition) tt.AssertEqual(parseStr(SeqRight(p1, p3), "ABC"), PState{input: "WXYZ", pos: 0, value: uint64(0), ok: true}) p4 := SeqRight(SetInput(u8.Text("XYZ")), GetInput) tt.AssertEqual(parseStr(SeqRight(p1, p4), "ABC"), PState{input: "XYZ", pos: 3, value: u8.Text("XYZ"), ok: true}) tt.AssertEqual(parseStr(Collect(p1, SeqRight(SetInputAndPosition(InputAndPosition{u8.Desur("XYZ"), 2}), p1)), "ABCDEFG"), //posn changed from 3 to 2... PState{input: "", pos: 5, value: arrText("ABC", "XYZ"), ok: true}) //...so posn is 5 instead of 6 }) }
//================================================================================ func TestAssert(t *testing.T) { ts.LogAsserts("Assert", t, func(tt *ts.T) { a := &A{make([]interface{}, 0, 10)} tt.Assert(len(a.slice) == 0) //(1) b := a.lengthenByOne() //tt.PrintValue(1234567890) //print test tt.Assert(len(b.slice) == 1) //(2) tt.Assert(len(a.slice) == 1) //(3) a.slice = a.slice[:3] tt.Assert(len(a.slice) == 3) //(4) tt.Assert(len(b.slice) == 3) //(5) c := a.lengthenByOne() tt.Assert(len(a.slice) == 4) //(6) tt.Assert(len(b.slice) == 4) //(7) tt.Assert(len(c.slice) == 4) //(8) tt.AssertPanic(func() { if len(c.slice) == 4 { panic("X") } //(9) }, "X") tt.AssertAnyPanic(func() { if len(c.slice) == 4 { panic("X") } //(10) }) /*tt.AssertPanic(func(){ if len(c.slice) == 4 { panic("X") } //(11) }, "Y")*/ //tt.Assert(false) //(12) force failure }) }
//================================================================================ func TestStateStruct(t *testing.T) { ts.LogAsserts("StateStruct", t, func(tt *ts.T) { type UserState struct { nlfound bool imports map[string]string } newUserState := UserState{ nlfound: true, imports: map[string]string{}, } tt.AssertEqual(parseStr(PutState(newUserState), ""), PState{ok: true, empty: true, user: UserState{nlfound: true, imports: map[string]string{}}}) unsetNlFound := func(u UserState) UserState { u.nlfound = false m := make(map[string]string) for a, b := range u.imports { m[a] = b } u.imports = m return u } modifyUserStateP := func(f func(UserState) UserState) Parser { return Bind(GetState, func(s interface{}) Parser { r := f(s.(UserState)) return SeqRight(PutState(r), Return(nil)) }) } tt.AssertEqual(parseStr(SeqRight(PutState(newUserState), modifyUserStateP(unsetNlFound)), ""), PState{ok: true, empty: true, user: UserState{imports: map[string]string{}}}) }) }
//================================================================================ func TestStateMap(t *testing.T) { ts.LogAsserts("StateMap", t, func(tt *ts.T) { init := PutStateMapEntry("counter", 123) //-------------------------------------------------------------------------------- getB := func(x interface{}) Parser { if x.(u8.Codepoint) == u8.Codepoint('\n') { return GetStateMapEntry("counter") } else { return Return(nil) } } p1 := SeqRight(init, Bind(AnyChar, getB)) tt.AssertEqual(parseStr(p1, "\nbc"), PState{input: "bc", pos: 1, value: 123, ok: true, user: map[string]interface{}{"counter": 123}}) tt.AssertEqual(parseStr(p1, "abc"), PState{input: "bc", pos: 1, value: nil, ok: true, user: map[string]interface{}{"counter": 123}}) //-------------------------------------------------------------------------------- solePutB := func(x interface{}) (p Parser) { if x.(u8.Codepoint) == u8.Codepoint('\n') { return Return(nil) } else { return PutStateMapEntry("counter", 777) } } p2 := SeqRight(init, Bind(AnyChar, solePutB)) tt.AssertEqual(parseStr(p2, "\nbc"), PState{input: "bc", pos: 1, value: nil, ok: true, user: map[string]interface{}{"counter": 123}}) tt.AssertEqual(parseStr(p2, "abc"), PState{input: "bc", pos: 1, value: map[string]interface{}{"counter": 123}, ok: true, user: map[string]interface{}{"counter": 777}}) //-------------------------------------------------------------------------------- putB := func(x interface{}) (p Parser) { if x.(u8.Codepoint) == u8.Codepoint('\n') { return GetStateMapEntry("counter") } else { return Bind(PutStateMapEntry("counter", 777), func(_ interface{}) Parser { return GetStateMapEntry("counter") }) } } p3 := SeqRight(init, Bind(AnyChar, putB)) tt.AssertEqual(parseStr(p3, "\nbc"), PState{input: "bc", pos: 1, value: 123, ok: true, user: map[string]interface{}{"counter": 123}}) tt.AssertEqual(parseStr(p3, "abc"), PState{input: "bc", pos: 1, value: 777, ok: true, user: map[string]interface{}{"counter": 777}}) p4 := Bind(AnyChar, putB) tt.AssertEqual(parseStr(p4, "\nbc"), PState{input: "bc", pos: 1, value: nil, ok: true}) tt.AssertEqual(parseStr(p4, "abc"), PState{input: "bc", pos: 1, value: 777, ok: true, user: map[string]interface{}{"counter": 777}}) p5 := SeqRight(Return(nil), Bind(AnyChar, putB)) tt.AssertEqual(parseStr(p5, "\nbc"), PState{input: "bc", pos: 1, value: nil, ok: true}) tt.AssertEqual(parseStr(p5, "abc"), PState{input: "bc", pos: 1, value: 777, ok: true, user: map[string]interface{}{"counter": 777}}) //-------------------------------------------------------------------------------- soleIncrIfNewline := func(x interface{}) Parser { if x.(u8.Codepoint) == u8.Codepoint('\n') { return ModifyStateMapEntry("counter", func(n interface{}, _ ...interface{}) interface{} { return n.(int) + 1 }) } else { return Return(nil) } } p20 := SeqRight(init, Bind(AnyChar, soleIncrIfNewline)) tt.AssertEqual(parseStr(p20, "\nbc"), PState{input: "bc", pos: 1, value: map[string]interface{}{"counter": 123}, ok: true, user: map[string]interface{}{"counter": 124}}) tt.AssertEqual(parseStr(p20, "abc"), PState{input: "bc", pos: 1, value: nil, ok: true, user: map[string]interface{}{"counter": 123}}) //-------------------------------------------------------------------------------- incrIfNewline := func(x interface{}) Parser { if x.(u8.Codepoint) == u8.Codepoint('\n') { return Bind(ModifyStateMapEntry("counter", func(n interface{}, _ ...interface{}) interface{} { return n.(int) + 1 }), func(_ interface{}) Parser { return GetStateMapEntry("counter") }) } else { return GetStateMapEntry("counter") } } p21 := SeqRight(init, Bind(AnyChar, incrIfNewline)) tt.AssertEqual(parseStr(p21, "\nbc"), PState{input: "bc", pos: 1, value: 124, ok: true, user: map[string]interface{}{"counter": 124}}) tt.AssertEqual(parseStr(p21, "abc"), PState{input: "bc", pos: 1, value: 123, ok: true, user: map[string]interface{}{"counter": 123}}) }) }
//================================================================================ func TestLexer(t *testing.T) { ts.LogAsserts("Lexer", t, func(tt *ts.T) { u := NewUnicodeLexer() tt.AssertEqual(parseStr(u.Letter(), "defg"), PState{input: "efg", pos: 1, value: u8.Text("d"), ok: true}) tt.AssertEqual(parseStr(u.Letter(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(u.Lower(), "defg"), PState{input: "efg", pos: 1, value: u8.Text("d"), ok: true}) tt.AssertEqual(parseStr(u.Lower(), "Defg"), PState{input: "Defg", empty: true, error: makeUnexpInp("D")}) tt.AssertEqual(parseStr(u.Lower(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(u.Upper(), "Defg"), PState{input: "efg", pos: 1, value: u8.Text("D"), ok: true}) tt.AssertEqual(parseStr(u.Upper(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(u.Upper(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(u.Digit(), "6efg"), PState{input: "efg", pos: 1, value: u8.Text("6"), ok: true}) tt.AssertEqual(parseStr(u.Digit(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(u.Whitespace(), " efg"), PState{input: "efg", pos: 1, value: u8.Codepoint(' '), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "\tefg"), PState{input: "efg", pos: 1, value: u8.Codepoint('\t'), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "\refg"), PState{input: "efg", pos: 1, value: u8.Codepoint('\r'), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "\nefg"), PState{input: "efg", pos: 1, value: u8.Codepoint('\n'), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "\fefg"), PState{input: "efg", pos: 1, value: u8.Codepoint('\f'), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "\vefg"), PState{input: "efg", pos: 1, value: u8.Codepoint('\v'), ok: true}) tt.AssertEqual(parseStr(u.Whitespace(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(u.Space(), " efg"), PState{input: "efg", pos: 1, value: u8.Text(" "), ok: true}) tt.AssertEqual(parseStr(u.Space(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) // TitlecaseLetter() Parser{ return Regexp(`\p{Lt}`) // ModifyingLetter() Parser{ return Regexp(`\p{Lm}`) // OtherLetter() Parser{ return Regexp(`\p{Lo}`) // Number() Parser{ return Regexp(`\pN`) // LetterNumber() Parser{ return Regexp(`\p{Nl}`) // OtherNumber() Parser{ return Regexp(`\p{No}`) // Mark() Parser{ return Regexp(`\pM`) // SpacingMark() Parser{ return Regexp(`\p{Mc}`) // EnclosingMark() Parser{ return Regexp(`\p{Me}`) // NonspacingMark() Parser{ return Regexp(`\p{Mn}`) // Punct() Parser{ return Regexp(`\pP`) // StartPunct() Parser{ return Regexp(`\p{Ps}`) // EndPunct() Parser{ return Regexp(`\p{Pe}`) // InitialPunct() Parser{ return Regexp(`\p{Pi}`) // FinalPunct() Parser{ return Regexp(`\p{Pf}`) // ConnectorPunct() Parser{ return Regexp(`\p{Pc}`) // DashPunct() Parser{ return Regexp(`\p{Pd}`) // OtherPunct() Parser{ return Regexp(`\p{Po}`) // Symbol() Parser{ return Regexp(`\pS`) // CurrencySymbol() Parser{ return Regexp(`\p{Sc}`) // MathSymbol() Parser{ return Regexp(`\p{Sm}`) // ModifierSymbol() Parser{ return Regexp(`\p{Sk}`) // OtherSymbol() Parser{ return Regexp(`\p{So}`) // Spacing() Parser{ return Regexp(`\pZ`) // LineSeparator() Parser{ return Regexp(`\p{Zl}`) // ParagraphSeparator() Parser{ return Regexp(`\p{Zp}`) // OtherCategory() Parser{ return Regexp(`\pC`) // Control() Parser{ return Regexp(`\p{Cc}`) // Format() Parser{ return Regexp(`\p{Cf}`) // PrivateUse() Parser{ return Regexp(`\p{Co}`) // Nonchar() Parser{ return Regexp(`\p{Cn}`) // Surrogate() Parser{ return Regexp(`\p{Cs}`) // Graphical() Parser{ return len(cc) == 1 && unicode.IsGraphic(cc[0]) // Printable() Parser{ return len(cc) == 1 && unicode.IsPrint(cc[0]) // SpecialControl() Parser{ return len(cc) == 1 && unicode.IsControl(cc[0]) // CommonScript() Parser{ return len(cc) == 1 && unicode.In(cc[0], unicode.Common) // InheritedScript() Parser{ return len(cc) == 1 && unicode.In(cc[0], unicode.Inherited) // UnicodeIn(ranges ...*unicode.RangeTable) Parser { return len(cc) == 1 && unicode.In(cc[0], ranges...) }) }
//================================================================================ func TestAsciiLexer(t *testing.T) { ts.LogAsserts("AsciiLexer", t, func(tt *ts.T) { a := NewAsciiLexer(false) at := NewAsciiLexer(true) tt.AssertEqual(parseStr(a.Letter(), "defg"), PState{input: "efg", pos: 1, value: u8.Text("d"), ok: true}) tt.AssertEqual(parseStr(a.Letter(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(a.Lower(), "defg"), PState{input: "efg", pos: 1, value: u8.Text("d"), ok: true}) tt.AssertEqual(parseStr(a.Lower(), "Defg"), PState{input: "Defg", empty: true, error: makeUnexpInp("D")}) tt.AssertEqual(parseStr(a.Lower(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(a.Upper(), "Defg"), PState{input: "efg", pos: 1, value: u8.Text("D"), ok: true}) tt.AssertEqual(parseStr(a.Upper(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(a.Upper(), ";efg"), PState{input: ";efg", empty: true, error: makeUnexpInp(";")}) tt.AssertEqual(parseStr(a.Digit(), "6efg"), PState{input: "efg", pos: 1, value: u8.Text("6"), ok: true}) tt.AssertEqual(parseStr(a.Digit(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(a.Space(), " efg"), PState{input: "efg", pos: 1, value: u8.Text(" "), ok: true}) tt.AssertEqual(parseStr(a.Space(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(a.Tab(), "\tefg"), PState{input: "efg", pos: 1, value: u8.Text("\t"), ok: true}) tt.AssertEqual(parseStr(a.Tab(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) tt.AssertEqual(parseStr(a.Newline(), "\nefg"), PState{input: "efg", pos: 1, value: u8.Text("\n"), ok: true}) tt.AssertEqual(parseStr(a.Newline(), "\r\nefg"), PState{input: "\r\nefg", empty: true, error: makeUnexpInp("\r")}) tt.AssertEqual(parseStr(at.Newline(), "\nefg"), PState{input: "efg", pos: 1, value: u8.Text("\n"), ok: true}) tt.AssertEqual(parseStr(at.Newline(), "\r\nefg"), PState{input: "efg", pos: 2, value: u8.Text("\r\n"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), " efg"), PState{input: "efg", pos: 1, value: u8.Text(" "), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "\tefg"), PState{input: "efg", pos: 1, value: u8.Text("\t"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "\refg"), PState{input: "efg", pos: 1, value: u8.Text("\r"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "\nefg"), PState{input: "efg", pos: 1, value: u8.Text("\n"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "\fefg"), PState{input: "efg", pos: 1, value: u8.Text("\f"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "\vefg"), PState{input: "efg", pos: 1, value: u8.Text("\v"), ok: true}) tt.AssertEqual(parseStr(a.Whitespace(), "defg"), PState{input: "defg", empty: true, error: makeUnexpInp("d")}) // Punct() Parser{ return Regexp(`[!"#%&'()*,\-./:;?@[\\\]_{}]`) // StartPunct() Parser{ return Regexp(`[([{]`) // EndPunct() Parser{ return Regexp(`[)\]}]`) // ConnectorPunct() Parser{ return Regexp(`_`) // DashPunct() Parser{ return Regexp(`-`) // OtherPunct() Parser{ return Regexp(`[!"#%&'*,./:;?@\\]`) // Symbol() Parser{ return Regexp(`[$+<=>^`+"`"+`|~]`) // CurrencySymbol() Parser{ return Regexp(`$`) // MathSymbol() Parser{ return Regexp(`[+<=>|~]`) // ModifierSymbol() Parser{ return Regexp(`[^`+"`"+`]`) // Control() Parser{ return Regexp(`[\x00-\x1F\x7F]`) //[:cntrl:] // Graphical() Parser{ return Regexp(`[\x21-\x7E]`) //[:graph:] // Printable() Parser{ return Regexp(`[\x20-\x7E]`) //[:print:] }) }