123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- package attl
- import "testing"
- import "reflect"
- type testCase struct {
- ParseFunc
- input string
- index int
- expectedIndex int
- expectError bool
- expectedValue Value
- }
- func (tc *testCase) Run(t *testing.T) {
- t.Logf("Test case input: %s", tc.input)
- res, err := tc.ParseFunc([]rune(tc.input), &tc.index)
- if tc.expectError {
- if err == nil {
- t.Errorf("expected parse error")
- return
- }
- } else {
- if err != nil {
- t.Errorf("error: unexpected parse error at %d: %v", tc.index, err)
- return
- }
- }
- if tc.index != tc.expectedIndex {
- if err == nil {
- t.Errorf("error: index not correct: %d <> %d", tc.index, tc.expectedIndex)
- }
- }
- if tc.expectedValue == nil {
- if res != nil {
- t.Errorf("error: expected nil value, got %v", res)
- } else {
- t.Logf("Test case value: nil")
- }
- } else {
- if res == nil {
- t.Errorf("error: expected value %v was nil", tc.expectedValue)
- } else {
- t.Logf("Test case value: %v", res)
- se := tc.expectedValue.String()
- so := res.String()
- if so != se {
- t.Errorf("error: value is not as expected: %s <-> %s", so, se)
- } else {
- if !reflect.DeepEqual(tc.expectedValue, res) {
- t.Errorf("error: values are not deeply equal: %s <-> %s", so, se)
- }
- }
- }
- }
- rs := []rune(tc.input)
- b := string(rs[0:tc.index])
- a := string(rs[tc.index:len(rs)])
- t.Logf("Test case index: %s|%s", b, a)
- }
- func TestParseComment(t *testing.T) {
- tcs := []testCase{
- testCase{ParseComment, "# comment\nnot comment", 0, 9, false, Comment("# comment")},
- testCase{ParseComment, "not comment\n#comment\n", 0, 0, false, nil},
- testCase{ParseComment, "# comment\nnot comment", 9, 9, false, nil},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseWs(t *testing.T) {
- tcs := []testCase{
- testCase{ParseWs, "# comment ", 0, 0, false, nil},
- testCase{ParseWs, "1234567890 ", 0, 0, false, nil},
- testCase{ParseWs, "-1234567890 ", 0, 0, false, nil},
- testCase{ParseWs, "+1234567890 ", 0, 0, false, nil},
- testCase{ParseWs, "`string` ", 0, 0, false, nil},
- testCase{ParseWs, `"string" `, 0, 0, false, nil},
- testCase{ParseWs, "word ", 0, 0, false, nil},
- testCase{ParseWs, " \tword ", 0, 2, false, String(" \t")},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseGetter(t *testing.T) {
- tcs := []testCase{
- testCase{ParseGetter, "not a getter ", 0, 0, false, nil},
- testCase{ParseGetter, "$# comment ", 0, 0, true, nil},
- testCase{ParseGetter, "$ bad space ", 0, 0, true, nil},
- testCase{ParseGetter, "$1234567890 ", 0, 11, false, Getter{Int(+1234567890)}},
- testCase{ParseGetter, "$-1234567890 ", 0, 12, false, Getter{Int(-1234567890)}},
- testCase{ParseGetter, "$+1234567890 ", 0, 12, false, Getter{Int(+1234567890)}},
- testCase{ParseGetter, "$`string` ", 0, 9, false, Getter{String("string")}},
- testCase{ParseGetter, `$"string" `, 0, 9, false, Getter{String("string")}},
- testCase{ParseGetter, "$word ", 0, 5, false, Getter{Word("word")}},
- testCase{ParseGetter, "$µ_rd ", 0, 5, false, Getter{Word("µ_rd")}},
- testCase{ParseGetter, "$wo09 ", 0, 5, false, Getter{Word("wo09")}},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseInteger(t *testing.T) {
- tcs := []testCase{
- testCase{ParseInteger, "01234567890 ", 0, 11, false, Int(1234567890)},
- testCase{ParseInteger, "-1234567890 ", 0, 11, false, Int(-1234567890)},
- testCase{ParseInteger, "+1234567890 ", 0, 11, false, Int(1234567890)},
- testCase{ParseInteger, "+1234567890", 0, 11, true, nil},
- testCase{ParseInteger, "not an integer", 0, 0, false, nil},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseString(t *testing.T) {
- tcs := []testCase{
- testCase{ParseString, `"string"`, 0, 8, false, String("string")},
- testCase{ParseString, `"string\"\n"`, 0, 12, false, String("string\"\n")},
- testCase{ParseString, `"bad `, 0, 12, true, nil},
- testCase{ParseString, `not a string`, 0, 0, false, nil},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseRawString(t *testing.T) {
- tcs := []testCase{
- testCase{ParseRawString, "`string` ", 0, 8, false, String("string")},
- testCase{ParseRawString, "`string\"quote` ", 0, 14, false,
- String("string\"quote")},
- testCase{ParseRawString, "`bad ", 0, 11, true, nil},
- testCase{ParseRawString, "not a string` ", 0, 0, false, nil},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseWord(t *testing.T) {
- tcs := []testCase{
- testCase{ParseWord, "word ", 0, 4, false, Word("word")},
- testCase{ParseWord, "word\n", 0, 4, false, Word("word")},
- testCase{ParseWord, "word; ", 0, 4, false, Word("word")},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseLiteral(t *testing.T) {
- tcs := []testCase{
- testCase{ParseLiteral, "# comment ", 0, 0, false, nil},
- testCase{ParseLiteral, " \t ", 0, 0, false, nil},
- testCase{ParseLiteral, "1234567890 ", 0, 10, false, Int(1234567890)},
- testCase{ParseLiteral, "-1234567890 ", 0, 11, false, Int(-1234567890)},
- testCase{ParseLiteral, "+1234567890 ", 0, 11, false, Int(1234567890)},
- testCase{ParseLiteral, "`string` ", 0, 8, false, String("string")},
- testCase{ParseLiteral, `"string" `, 0, 8, false, String("string")},
- testCase{ParseLiteral, "word ", 0, 4, false, Word("word")},
- testCase{ParseLiteral, "µ_rd ", 0, 4, false, Word("µ_rd")},
- testCase{ParseLiteral, "wo09 ", 0, 4, false, Word("wo09")},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseParameters(t *testing.T) {
- tcs := []testCase{
- testCase{ParseParameters, " world\n", 0, 6, false, List{Word("world")}},
- testCase{ParseParameters, ` world 7 "foo"` + "`\n", 0, 14, false,
- List{Word("world"), Int(7), String("foo")},
- },
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseOrder(t *testing.T) {
- tcs := []testCase{
- testCase{ParseOrder, "hello ", 0, 5, false, Word("hello")},
- testCase{ParseOrder, "1 ", 0, 1, false, Int(1)},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseCommand(t *testing.T) {
- tcs := []testCase{
- testCase{ParseCommand, "hello world\n", 0, 11, false,
- Command{Word("hello"), List{Word("world")}},
- },
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseEvaluation(t *testing.T) {
- tcs := []testCase{
- testCase{ParseEvaluation, "[hello world]", 0, 13, false,
- Evaluation{Command{Word("hello"), List{Word("world")}}},
- },
- testCase{ParseEvaluation, "[hello 123 ]", 0, 12, false,
- Evaluation{Command{Word("hello"), List{Int(123)}}},
- },
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseAStatement(t *testing.T) {
- tcs := []testCase{
- testCase{ParseStatement, " hello world\n", 0, 12, false,
- Command{Word("hello"), List{Word("world")}},
- },
- testCase{ParseStatement, " hello;world;", 0, 6, false,
- Command{Word("hello"), List{}},
- },
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseStatements(t *testing.T) {
- tcs := []testCase{
- testCase{ParseStatements, "\n\n\n", 0, 3, false,
- List{},
- },
- testCase{ParseStatements, "\n\n \n", 0, 4, false,
- List{},
- },
- testCase{ParseStatements, "hello world\n", 0, 12, false,
- List{Command{Word("hello"), List{Word("world")}}},
- },
- testCase{ParseStatements, "hello;world;", 0, 12, false,
- List{Command{Word("hello"), List{}}, Command{Word("world"), List{}}},
- },
- testCase{ParseStatements, "hello \n world \n\n", 0, 16, false,
- List{Command{Word("hello"), List{}}, Command{Word("world"), List{}}},
- },
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseBlock(t *testing.T) {
- tcs := []testCase{
- testCase{ParseBlock, "{hello world}", 0, 13, false,
- Block{List{Command{Word("hello"), List{Word("world")}}}},
- },
- testCase{ParseBlock, "{hello;world}", 0, 13, false,
- Block{List{Command{Word("hello"), List{}}, Command{Word("world"), List{}}}},
- },
- testCase{ParseBlock, "{hello\nworld}", 0, 13, false,
- Block{List{Command{Word("hello"), List{}}, Command{Word("world"), List{}}}},
- },
- testCase{ParseBlock, "{ hello\n world\n}", 0, 16, false,
- Block{List{Command{Word("hello"), List{}}, Command{Word("world"), List{}}}},
- },
- testCase{ParseBlock, "{ #Comment\n hello\n world\n}", 0, 26, false,
- Block{List{Comment("#Comment"), Command{Word("hello"), List{}}, Command{Word("world"), List{}}}}},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParse(t *testing.T) {
- script1 := `
- # Comment
- print "Hello world!"
- `
- res1 := Block{List{Comment("# Comment"), Command{Word("print"), List{String("Hello world!")}}}}
- script2 := `
- # Comment
- print "Hello world!"
- `
- res2 := Block{List{Comment("# Comment"), Command{Word("print"), List{String("Hello world!")}}}}
- tcs := []testCase{
- testCase{ParseScript, script1, 0, len(script1), false, res1},
- testCase{ParseScript, script2, 0, len(script1), false, res2},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t)
- }
- }
- func TestParseAndRun(t *testing.T) {
- script1 := `
- # Comment
- print "Hello world!"
- `
- parsed, err := Parse(script1)
- if err != nil {
- t.Errorf("Parse error: %v", err)
- return
- }
- if parsed == nil {
- t.Errorf("No parse results error: %v", parsed)
- return
- }
- env := &Environment{}
- env.Push()
- env.Define("print", Proc(func(e *Environment, args ...Value) (Value, Effect) {
- var msg string
- Args(args, &msg)
- print(msg, "\n")
- return nil, nil
- }), 0)
- parsed.Eval(env)
- }
- type iTestCase struct {
- in string
- ex string
- expectError bool
- args []Value
- }
- func (tc *iTestCase) Run(t *testing.T, e Environment) {
- t.Logf("Test case input: %s", tc.in)
- res := e.Interpolate(tc.in, tc.args...)
- t.Logf("Test case result: %v", res)
- if res != tc.ex {
- t.Errorf("error: value not expected: %s <-> %s", res, tc.ex)
- }
- }
- func TestInterpolate(t *testing.T) {
- e := Environment{}
- e.Push()
- e.Define("foo", String("{world}"), 0)
- tcs := []iTestCase{
- iTestCase{`hello {world}`, `hello {world}`, false, []Value{}},
- iTestCase{`hello ${foo}`, `hello {world}`, false, []Value{}},
- iTestCase{`hello $${foo}`, `hello ${foo}`, false, []Value{}},
- iTestCase{`hello ${1}`, `hello {world}`, false, []Value{String("{world}")}},
- }
- for i, tc := range tcs {
- t.Logf("Case: %d", i+1)
- tc.Run(t, e)
- }
- }
|