Source

units / parse_test.go

Full commit
package units

import "testing"

var parseUnitTable = []struct {
	input string
	si    string
	ok    bool
}{
	{"m", "1m", true},
	{"Fonzis", "0", false},
	{"xxxxx", "0", false},
	{"min", "60s", true},
	{"uin", "25.4nm", true},
	{"kg", "1kg", true},
	{"ml", "1mL", true},

	{"m//s", "0", false},
	{"m/s/", "0", false},
	{"*m/s", "0", false},
	{"m/s", "1m/s", true},
	{"kg*m/s*s", "1N", true},
}

func TestParseUnit(t *testing.T) {
	for _, entry := range parseUnitTable {
		v, ok := parseUnit(entry.input)
		si := v.String()
		if ok != entry.ok || si != entry.si {
			t.Errorf("%q should parse as %q,%t; but got %q,%t",
				entry.input, entry.si, entry.ok, si, ok)
		}
	}
}

var tokenTable = []struct {
	src    string
	fail   bool
	tokens []string
}{
	{"", false, nil},
	{"1m", false, []string{"1", "m"}},
	{"m1", false, []string{"m", "1"}}, // It's the parser's job to reject this
	{"22nm*(4.5kN+.99N)", false,
		[]string{"22", "nm", "*", "(", "4.5", "kN", "+", ".99", "N", ")"}},
	{" 22 nm * ( 4.5 kN + .99 N ) ", false,
		[]string{"22", "nm", "*", "(", "4.5", "kN", "+", ".99", "N", ")"}},

	{"1.2e9", false, []string{"1.2e9"}},
	{"1.2e9+.8e9", false, []string{"1.2e9", "+", ".8e9"}},
	{"1.2e-9m", false, []string{"1.2e-9", "m"}},

	{"10m/s*10N", false, []string{"10", "m/s", "*", "10", "N"}},
}

func TestTokenizer(t *testing.T) {
	for _, entry := range tokenTable {
		tokens, err := tokenize(entry.src)

		if entry.fail && err == nil {
			t.Errorf("Tokenizing %q: expected error, but got no error.")
		}
		if !entry.fail && err != nil {
			t.Errorf("Tokenizing %q: expected no error, got %q",
				entry.src, err.Error())
		}

		tokenMatch := true
		if len(tokens) != len(entry.tokens) {
			tokenMatch = false
		} else {
			for i := 0; i < len(tokens); i += 1 {
				if tokens[i] != entry.tokens[i] {
					tokenMatch = false
				}
			}
		}
		if !tokenMatch {
			t.Errorf("Tokenizing %q: expected tokens %v, got %v",
				entry.src, entry.tokens, tokens)
		}
	}
}

var parsingTable = []struct {
	src  string
	fail bool
	out  string
}{
	{"1m+200mm", false, "1.2m"},
	{"1m * 2", false, "2m"},
	{"1in in mm", false, "25.4mm"},
	{"1J + 1N*1m - 1W*1s", false, "1J"},
	{"3600J/(.5h+1800s)", false, "1W"},
	{"3+4*2/(1-5)", false, "1"},
	{"1e-9kg*m/s*s*1e9m/s", false, "1W"},

	{"", true, ""},
	{"(3+2) (2*3)", true, ""},
	{"45mm + 22s", true, ""},
	{"(5*2", true, ""},
	{"1+2)", true, ""},
	{"10J m", true, ""},
	{"3+", true, ""},
	{"*3", true, ""},
}

func TestParsing(t *testing.T) {
	for _, entry := range parsingTable {
		out, err := Parse(entry.src)

		if entry.fail && err == nil {
			t.Errorf("Parsing %q: expected error, but got no error.")
		}
		if !entry.fail && err != nil {
			t.Errorf("Parsing %q: expected no error, got %q",
				entry.src, err.Error())
		}

		if err != nil {
			continue
		}
		outstr := out.String()
		if entry.out != outstr {
			t.Errorf("Parsing %q: expected %q, got %q",
				entry.src, entry.out, outstr)
		}
	}
}

func BenchmarkParse(b *testing.B) {
	input := "10mW*(1h+20min+33s+250ms) + (25mN*10km) - 30J"
	for i := 0; i < b.N; i++ {
		out, _ := Parse(input)
		out.String()
	}
}