go测试失败,空切片JSON应该在哪里

时间:2017-11-14 06:50:48

标签: json go marshalling

我正在测试一段名为Compile的代码:

// Compile takes in code, and returns JSON
// bytes and an error if there was one
func Compile(in string) ([]byte, error) {
    // iterate through every line in the code
    for _, line := range strings.Split(in, "\n") {
        // Divide the line into sections
        // for easier processing
        tokens := strings.Split(line, " ")
        for _, a := range availableExpressions {
            for _, b := range availableStatements {
                if tokens[1] == b {
                    // It is an expression, so
                    // calculate the value of
                    // the expression
                    var val int
                    num1, err := strconv.Atoi(tokens[0])
                    if err != nil {
                        return nil, err
                    }
                    num2, err := strconv.Atoi(tokens[1])
                    if err != nil {
                        return nil, err
                    }
                    args := []int{num1, num2}
                    switch b {
                    case "+":
                        val = args[0] + args[1]
                    case "*":
                        val = args[0] * args[1]
                    case "-":
                        val = args[0] - args[1]
                    case "/":
                        val = args[0] / args[1]
                    }
                    cmd := &Mixed{
                        isExpression: true,
                        isStatement:  false,
                        Value: &Expression{
                            Name: b,
                            // for some reason go doesn't
                            // let me put args directly
                            Arguments: []interface{}{args},
                            Value:     val,
                        }}
                    fmt.Println(cmd.Value)
                    commands = append(commands, cmd)
                } else if tokens[0] == a {
                    // argument is a statement, don't bother
                    // to evaluate the value
                    arguments := strings.Join(tokens[1:], " ")
                    cmd := &Mixed{
                        isStatement:  true,
                        isExpression: false,
                        Value: &Statement{
                            Name:      a,
                            Arguments: []interface{}{arguments},
                        }}
                    fmt.Println(cmd.Value)
                    commands = append(commands, cmd)
                }
            }
        }
    }
    gen, err := json.Marshal(commands)
    // fmt prints an empty slice
    // no matter what is in
    fmt.Println(commands)
    // empty the commands
    commands = make([]*Mixed, 0)
    if err != nil {
        return nil, err
    }
    return gen, nil
}

但是在运行测试时:

$ cat compile_test.go
package main

import "fmt"
import "testing"

func TestCompile(t *testing.T) {
    cases := []struct {
        in  string
        out string
    }{
        {
            in:  "print \"Hello World\"",
            out: "[{\"Name\":\"print\",\"Arguments\":[\"Hello World\"]}]",
        },
        {
            in:  "print \"My name is Jack White\"",
            out: "[{\"Name\":\"print\",\"Arguments\":[\"My name is Jack White\"]}]",
        },
    }
    real_stuff, err := Compile(cases[0].in)
    if err != nil {
        fmt.Printf("error: %s\n", err)
    }
    if string(real_stuff) != cases[0].out {
        fmt.Printf("got %s, expected %s\n", string(real_stuff), cases[0].out)
        t.Fail()
    }
    real_stuff, err = Compile(cases[1].in)
    if err != nil {
        fmt.Printf("error: %s\n", err)
    }
    if string(real_stuff) != cases[1].out {
        fmt.Printf("got %s, expected %s\n", string(real_stuff), cases[1].out)
        t.Fail()
    }
}
$ go test
[]
got [], expected [{"Name":"print","Arguments":["Hello World"]}]
[]
got [], expected [{"Name":"print","Arguments":["My name is Jack White"]}]
--- FAIL: TestCompile (0.06s)

有人可以解释为什么测试失败以及为什么Compile不起作用?

1 个答案:

答案 0 :(得分:1)

您需要调试代码逻辑:

我换了:

    for _, a := range availableExpressions {
        for _, b := range availableStatements {

使用:

    for _, a := range availableStatements {
        for _, b := range availableExpressions {

运行this

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "strconv"
    "strings"
)

// Function not implemented yet,
// but there for completedness
type Function struct {
    Name      string
    Arguments []interface{}
    // A function can contain
    // both expressions and
    // statements
    Code []Mixed
}

// Mixed can be either Statement
// or Expression
type Mixed struct {
    isStatement  bool
    isExpression bool
    Value        interface{}
}

// Statement represents
// statements. How a statement
// is used is entirely up to
// the interpreter.
type Statement struct {
    Name      string
    Arguments []interface{}
}

// Since an Expression
// is calculated beforehand,
// store the value
type Expression struct {
    Name      string
    Arguments []interface{}
    Value     interface{}
}

// commands contains commands to
// execute later.
// It is of type Mixed because Mixed
// can be of type Expression or Statement
var commands = make([]*Mixed, 0)

var availableStatements = []string{
    "print",
}
var availableExpressions = []string{
    "+",
    "-",
    "*",
    "/",
}

// Compile takes in code, and returns JSON
// bytes and an error if there was one
func Compile(in string) ([]byte, error) {
    // iterate through every line in the code
    for _, line := range strings.Split(in, "\n") {
        // Divide the line into sections
        // for easier processing
        tokens := strings.Split(line, " ")
        for _, a := range availableStatements {
            for _, b := range availableExpressions {
                if tokens[1] == b {
                    // It is an expression, so
                    // calculate the value of
                    // the expression
                    var val int
                    num1, err := strconv.Atoi(tokens[0])
                    if err != nil {
                        return nil, err
                    }
                    num2, err := strconv.Atoi(tokens[1])
                    if err != nil {
                        return nil, err
                    }
                    args := []int{num1, num2}
                    switch b {
                    case "+":
                        val = args[0] + args[1]
                    case "*":
                        val = args[0] * args[1]
                    case "-":
                        val = args[0] - args[1]
                    case "/":
                        val = args[0] / args[1]
                    }
                    cmd := &Mixed{
                        isExpression: true,
                        isStatement:  false,
                        Value: &Expression{
                            Name: b,
                            // for some reason go doesn't
                            // let me put args directly
                            Arguments: []interface{}{args},
                            Value:     val,
                        }}
                    fmt.Println(cmd.Value)
                    commands = append(commands, cmd)
                } else if tokens[0] == a {
                    // argument is a statement, don't bother
                    // to evaluate the value
                    arguments := strings.Join(tokens[1:], " ")
                    cmd := &Mixed{
                        isStatement:  true,
                        isExpression: false,
                        Value: &Statement{
                            Name:      a,
                            Arguments: []interface{}{arguments},
                        }}
                    fmt.Println(cmd.Value)
                    commands = append(commands, cmd)
                }
            }
        }
    }
    gen, err := json.Marshal(commands)
    fmt.Println(commands)
    // empty the commands
    commands = make([]*Mixed, 0)
    if err != nil {
        return nil, err
    }
    return gen, nil
}

func Execute(input_file string) error {
    // open input file
    f, err := ioutil.ReadFile(input_file)
    if err != nil {
        return err
    }
    // unmarshal the JSON
    var data []*Mixed
    err = json.Unmarshal(f, data)
    if err != nil {
        return err
    }
    for _, v := range data {
        var a *Expression
        var b *Statement
        // get absolute value of v
        if v.isExpression {
            a = v.Value.(*Expression)
            b = nil
        } else if v.isStatement {
            b = v.Value.(*Statement)
            a = nil
        }
        // since the expression is
        // already calculated at compile-time,
        // don't bother evaluating
        if a != nil {
            fmt.Println(a.Value)
        }
        if b != nil {
            // on the other hand, evaluate
            // statements since they're *not*
            // evaluated at compile-time
            switch b.Name {
            case "print":
                for _, n := range b.Arguments {
                    fmt.Printf("%v", n)
                }
                fmt.Printf("\n")
            }
        }
    }
    return nil
}

func main() {
    cases := []struct {
        in  string
        out string
    }{
        {
            in:  "print \"Hello World\"",
            out: "[{\"Name\":\"print\",\"Arguments\":[\"Hello World\"]}]",
        },
        {
            in:  "print \"My name is Jack White\"",
            out: "[{\"Name\":\"print\",\"Arguments\":[\"My name is Jack White\"]}]",
        },
    }
    real_stuff, err := Compile(cases[0].in)
    if err != nil {
        fmt.Printf("error: %s\n", err)
    }
    fmt.Println(string(real_stuff))
    if string(real_stuff) != cases[0].out {
        fmt.Printf("got %s, expected %s\n", string(real_stuff), cases[0].out)
        //t.Fail()
    }
    real_stuff, err = Compile(cases[1].in)
    if err != nil {
        fmt.Printf("error: %s\n", err)
    }
    fmt.Println(string(real_stuff))
    if string(real_stuff) != cases[1].out {
        fmt.Printf("got %s, expected %s\n", string(real_stuff), cases[1].out)
        //t.Fail()
    }
}

输出(go test):

&{print ["Hello World"]}
&{print ["Hello World"]}
&{print ["Hello World"]}
&{print ["Hello World"]}
[0xc04204e3c0 0xc04204e420 0xc04204e460 0xc04204e4c0]
got [{"Value":{"Name":"print","Arguments":["\"Hello World\""]}},{"Value":{"Name":"print","Arguments":["\"Hello World\""]}},{"Value":{"Name":"print","Arguments":["\"Hello World\""]}},{"Value":{"Name":"print","Arguments":["\"Hello World\""]}}], expected [{"Name":"print","Arguments":["Hello World"]}]
&{print ["My name is Jack White"]}
&{print ["My name is Jack White"]}
&{print ["My name is Jack White"]}
&{print ["My name is Jack White"]}
[0xc04204e6e0 0xc04204e720 0xc04204e760 0xc04204e7c0]
got [{"Value":{"Name":"print","Arguments":["\"My name is Jack White\""]}},{"Value":{"Name":"print","Arguments":["\"My name is Jack White\""]}},{"Value":{"Name":"print","Arguments":["\"My name is Jack White\""]}},{"Value":{"Name":"print","Arguments":["\"My name is Jack White\""]}}], expected [{"Name":"print","Arguments":["My name is Jack White"]}]
--- FAIL: TestCompile (0.00s)
FAIL
exit status 1
FAIL    ar/sogo 0.016s