func TestPythonToGoString(t *testing.T) { t.Parallel() expectations := []struct { in, out, left string }{ {`''`, `""`, ``}, {`''\'`, `""`, `\'`}, {`'''`, `""`, `'`}, {`""`, `""`, ``}, {`"" and`, `""`, ` and`}, {`'"' "w`, `"\""`, ` "w`}, {`"'"`, `"'"`, ``}, {`"\'"`, `"'"`, ``}, {`"ok" or`, `"ok"`, ` or`}, {`'\\"\\'`, `"\\\"\\"`, ``}, {`"\\\"\\"`, `"\\\"\\"`, ``}, {`"'\\'"`, `"'\\'"`, ``}, {`'"\'\'"'`, `"\"''\""`, ``}, {`'"\'\'"'`, `"\"''\""`, ``}, {`'∀ unicode'`, `"∀ unicode"`, ``}, } for i, e := range expectations { goChunk, left, err := pythonToGoString(stringToRunes(e.in)) t.Logf("in: `%s` eg: `%s` g: `%s` el: `%s` l: `%s` err: %s", e.in, e.out, goChunk, e.left, string(left), err) ut.AssertEqualIndex(t, i, e.left, string(left)) ut.AssertEqualIndex(t, i, e.out, goChunk) ut.AssertEqualIndex(t, i, nil, err) } }
func TestMatchConfigs(t *testing.T) { t.Parallel() unbound := "unbound" // Treated specially by makeVVs to create unbound variableValue. expectations := []struct { cond string conf []string all [][]variableValue out [][]variableValue }{ {"OS==\"win\"", []string{"OS"}, [][]variableValue{makeVVs("win"), makeVVs("mac"), makeVVs("linux")}, [][]variableValue{makeVVs("win")}, }, {"(foo==1 or foo==2) and bar==\"b\"", []string{"foo", "bar"}, [][]variableValue{makeVVs("1", "a"), makeVVs("1", "b"), makeVVs("2", "a"), makeVVs("2", "b")}, [][]variableValue{makeVVs("1", "b"), makeVVs("2", "b")}, }, {"bar==\"b\"", []string{"foo", "bar"}, [][]variableValue{makeVVs("1", "a"), makeVVs("1", "b"), makeVVs("2", "a"), makeVVs("2", "b")}, [][]variableValue{makeVVs("1", "b"), makeVVs("2", "b"), makeVVs(unbound, "b")}, }, {"foo==1 or bar==\"b\"", []string{"foo", "bar"}, [][]variableValue{makeVVs("1", "a"), makeVVs("1", "b"), makeVVs("2", "a"), makeVVs("2", "b")}, [][]variableValue{makeVVs("1", "a"), makeVVs("1", "b"), makeVVs("2", "b"), makeVVs("1", unbound)}, }, } for i, e := range expectations { c, err := processCondition(condition{Condition: e.cond}, variablesValuesSet{}) ut.AssertEqualIndex(t, i, nil, err) out := c.matchConfigs(makeConfigVariableIndex(e.conf), e.all) ut.AssertEqualIndex(t, i, vvToStr2D(vvSort(e.out)), vvToStr2D(vvSort(out))) } }
func TestConditionEvaluate(t *testing.T) { t.Parallel() const ( T int = 1 F int = 0 E int = -1 ) expectations := []struct { cond string vals map[string]string exp int }{ {"A=='w'", map[string]string{"A": "w"}, T}, {"A=='m'", map[string]string{"A": "w"}, F}, {"A=='m'", map[string]string{"a": "w"}, E}, {"A==1 or B=='b'", map[string]string{"A": "1"}, T}, {"A==1 or B=='b'", map[string]string{"B": "b"}, E}, {"A==1 and B=='b'", map[string]string{"A": "1"}, E}, {"(A=='w')", map[string]string{"A": "w"}, T}, {"A==1 or (B==2 and C==3)", map[string]string{"A": "1"}, T}, {"A==1 or (B==2 and C==3)", map[string]string{"A": "0"}, E}, {"A==1 or (B==2 and C==3)", map[string]string{"A": "0", "B": "0"}, F}, {"A==1 or (B==2 and C==3)", map[string]string{"A": "2", "B": "2"}, E}, {"A==1 or (B==2 and C==3)", map[string]string{"A": "2", "B": "2", "C": "3"}, T}, {"(A==1 or A==2) and B==3", map[string]string{"A": "1", "B": "3"}, T}, {"(A==1 or A==2) and B==3", map[string]string{"A": "2", "B": "3"}, T}, {"(A==1 or A==2) and B==3", map[string]string{"B": "3"}, E}, } for i, e := range expectations { c, err := processCondition(condition{Condition: e.cond}, variablesValuesSet{}) ut.AssertEqualIndex(t, i, nil, err) isTrue, err := c.evaluate(func(v string) variableValue { if value, ok := e.vals[v]; ok { return makeVariableValue(value) } assert(variableValue{}.isBound() == false) return variableValue{} }) if e.exp == E { ut.AssertEqualIndex(t, i, errors.New("required variable is unbound"), err) } else { ut.AssertEqualIndex(t, i, nil, err) ut.AssertEqualIndex(t, i, e.exp == T, isTrue) } } }
func TestCheckURL(t *testing.T) { data := []struct { in string expected string err error }{ {"foo", "https://foo", nil}, {"https://foo", "https://foo", nil}, {"http://foo.example.com", "http://foo.example.com", nil}, {"http://foo.appspot.com", "", errors.New("only https:// scheme is accepted for appspot hosts, it can be omitted")}, } for i, line := range data { out, err := CheckURL(line.in) ut.AssertEqualIndex(t, i, line.expected, out) ut.AssertEqualIndex(t, i, line.err, err) } }
func TestPythonToGoStringError(t *testing.T) { t.Parallel() expErr := errors.New("failed to parse Condition string") for i, e := range []string{`'"`, `"'`, `'\'`, `"\"`, `'""`, `"''`} { goChunk, left, err := pythonToGoString(stringToRunes(e)) t.Logf("in: `%s`, g: `%s`, l: `%s`, err: %s", e, goChunk, string(left), err) ut.AssertEqualIndex(t, i, expErr, err) } }
func TestPythonToGoNonString(t *testing.T) { t.Parallel() expectations := []struct { in, out, left string }{ {`and`, `&&`, ``}, {`or`, `||`, ``}, {` or('str'`, ` ||(`, `'str'`}, {`)or(`, `)||(`, ``}, {`andor`, `andor`, ``}, {`)whatever("string...`, `)whatever(`, `"string...`}, } for i, e := range expectations { goChunk, left := pythonToGoNonString(stringToRunes(e.in)) t.Logf("in: `%s` eg: `%s` g: `%s` el: `%s` l: `%s`", e.in, e.out, goChunk, e.left, string(left)) ut.AssertEqualIndex(t, i, e.left, string(left)) ut.AssertEqualIndex(t, i, e.out, goChunk) } }
func TestHexDigestValid(t *testing.T) { t.Parallel() valid := []string{ "0123456789012345678901234567890123456789", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", } for i, in := range valid { ut.AssertEqualIndex(t, i, true, HexDigest(in).Validate()) } }
func TestHexDigestInvalid(t *testing.T) { t.Parallel() invalid := []string{ "0123456789", "AAAAAAAAAA", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", } for i, in := range invalid { ut.AssertEqualIndex(t, i, false, HexDigest(in).Validate()) } }
func TestPrefixSpace(t *testing.T) { t.Parallel() type S struct { i int s string } checks := map[int]S{ 0: {0, ""}, 1: {16, "f"}, 2: {256, "ff"}, 3: {4096, "fff"}, 4: {65536, "ffff"}, } for prefixLength, s := range checks { x := prefixSpace(uint(prefixLength)) ut.AssertEqualIndex(t, prefixLength, x, s.i) if x != 0 { res := fmt.Sprintf("%0*x", prefixLength, x-1) ut.AssertEqualIndex(t, prefixLength, res, s.s) } } }
func TestProcessConditionBad(t *testing.T) { t.Parallel() expectations := []string{ "wrong condition1", "invalidConditionOp is False", "a == 1.1", // Python isolate_format is actually OK with this. "a = 1", } for i, e := range expectations { _, err := processCondition(condition{Condition: e}, variablesValuesSet{}) ut.AssertEqualIndex(t, i, true, err != nil) } }
func TestProcessModes(t *testing.T) { data := []struct { in string expected []checks.Mode err error }{ {"all", []checks.Mode{checks.ContinuousIntegration, checks.Lint}, nil}, {"", nil, nil}, {"pc", []checks.Mode{checks.PreCommit}, nil}, {"fast", []checks.Mode{checks.PreCommit}, nil}, {"pp", []checks.Mode{checks.PrePush}, nil}, {"slow", []checks.Mode{checks.PrePush}, nil}, {"ci", []checks.Mode{checks.ContinuousIntegration}, nil}, {"full", []checks.Mode{checks.ContinuousIntegration}, nil}, {"foo", nil, errors.New("invalid mode \"foo\"\n\n" + helpModes)}, } for i, line := range data { actual, err := processModes(line.in) ut.AssertEqualIndex(t, i, line.expected, actual) ut.AssertEqualIndex(t, i, line.err, err) } }
func TestIsMainPackage(t *testing.T) { t.Parallel() data := []struct { expected string in string }{ {"foo", "// Hi\npackage foo\n"}, {"main", "package main\n"}, {"", ""}, } for i, line := range data { ut.AssertEqualIndex(t, i, line.expected, getPackageName([]byte(line.in))) } }
func TestProcess(t *testing.T) { // 2 goroutines with the same signature data := []string{ "panic: runtime error: index out of range", "", "goroutine 11 [running, 5 minutes, locked to thread]:", "github.com/luci/luci-go/client/archiver.(*archiver).PushFile(0xc208032410, 0xc20968a3c0, 0x5b, 0xc20988c280, 0x7d, 0x0, 0x0)", " /gopath/src/github.com/luci/luci-go/client/archiver/archiver.go:325 +0x2c4", "github.com/luci/luci-go/client/isolate.archive(0x7fbdab7a5218, 0xc208032410, 0xc20803b0b0, 0x22, 0xc208046370, 0xc20804666a, 0x17, 0x0, 0x0, 0x0, ...)", " /gopath/src/github.com/luci/luci-go/client/isolate/isolate.go:148 +0x12d2", "github.com/luci/luci-go/client/isolate.Archive(0x7fbdab7a5218, 0xc208032410, 0xc20803b0b0, 0x22, 0xc208046370, 0x0, 0x0)", " /gopath/src/github.com/luci/luci-go/client/isolate/isolate.go:102 +0xc9", "main.func·004(0x7fffc3b8f13a, 0x2c)", " /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:166 +0x7cd", "created by main.(*batchArchiveRun).main", " /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:167 +0x42c", "", "goroutine 1 [running]:", "gopkg.in/yaml%2ev2.handleErr(0xc208033b20)", " /gopath/src/gopkg.in/yaml.v2/yaml.go:153 +0xc6", "reflect.Value.assignTo(0x570860, 0xc20803f3e0, 0x15)", " " + goroot + "/src/reflect/value.go:2125 +0x368", "main.main()", " /gopath/src/github.com/maruel/pre-commit-go/main.go:428 +0x27", "", } out := &bytes.Buffer{} err := Process(bytes.NewBufferString(strings.Join(data, "\n")), out) ut.AssertEqual(t, nil, err) expected := []string{ "panic: runtime error: index out of range", "", "\x1b[95m1: running [5 minutes] [locked]\x1b[90m [Created by main.(*batchArchiveRun).main @ batch_archive.go:167]\x1b[0m", " \x1b[97marchiver\x1b[0m archiver.go:325 \x1b[91m(*archiver).PushFile\x1b[0m(#1, 0xc20968a3c0, 0x5b, 0xc20988c280, 0x7d, 0, 0)", " \x1b[97misolate \x1b[0m isolate.go:148 \x1b[31marchive\x1b[0m(#4, #1, #2, 0x22, #3, 0xc20804666a, 0x17, 0, 0, 0, ...)", " \x1b[97misolate \x1b[0m isolate.go:102 \x1b[91mArchive\x1b[0m(#4, #1, #2, 0x22, #3, 0, 0)", " \x1b[97mmain \x1b[0m batch_archive.go:166 \x1b[93mfunc·004\x1b[0m(0x7fffc3b8f13a, 0x2c)", "\x1b[37m1: running\x1b[0m", " \x1b[97myaml.v2 \x1b[0m yaml.go:153 \x1b[31mhandleErr\x1b[0m(#5)", " \x1b[97mreflect \x1b[0m value.go:2125 \x1b[32mValue.assignTo\x1b[0m(0x570860, #6, 0x15)", " \x1b[97mmain \x1b[0m main.go:428 \x1b[93mmain\x1b[0m()", "", } actual := strings.Split(out.String(), "\n") for i := 0; i < len(actual) && i < len(expected); i++ { ut.AssertEqualIndex(t, i, expected[i], actual[i]) } ut.AssertEqual(t, expected, actual) }
func TestConvertPyToGoArchiveCMDArgs(t *testing.T) { t.Parallel() data := []struct { input []string expected []string }{ // Simple. { []string{"--path-variable", "key=value"}, []string{"--path-variable", "key=value"}, }, { []string{"--path-variable", "key", "value1"}, []string{"--path-variable", "key=value1"}, }, // That's how python isolate works. { []string{"--extra-variable", "key", "and spaces"}, []string{"--extra-variable", "key=and spaces"}, }, { []string{"--path-variable", "key", "--even-this-value"}, []string{"--path-variable", "key=--even-this-value"}, }, // Other args. { []string{"-x", "--var", "--config-variable", "key", "value"}, []string{"-x", "--var", "--config-variable", "key=value"}, }, { []string{"--path-variable", "key", "value", "posarg"}, []string{"--path-variable", "key=value", "posarg"}, }, // Too few args are just ignored. { []string{"--path-variable"}, []string{"--path-variable"}, }, { []string{"--path-variable", "key-and-no-value"}, []string{"--path-variable", "key-and-no-value"}, }, } for i, line := range data { ut.AssertEqualIndex(t, i, line.expected, convertPyToGoArchiveCMDArgs(line.input)) } }
func TestParseBadIsolate(t *testing.T) { t.Parallel() // These tests make Python spill out errors into stderr, which might be confusing. // However, when real isolate command runs, we want to see these errors. badIsolates := []string{ "statement = 'is not good'", "{'includes': map(str, [1,2])}", "{ python/isolate syntax error", "{'wrong_section': False, 'includes': 'must be a list'}", "{'conditions': ['must be list of conditions', {}]}", "{'conditions': [['', {'variables-missing': {}}]]}", "{'variables': ['bad variables type']}", } for i, badIsolate := range badIsolates { _, err := processIsolate([]byte(badIsolate)) ut.AssertEqualIndex(t, i, true, err != nil) } }
func TestRound(t *testing.T) { t.Parallel() data := []struct { in time.Duration round time.Duration expected time.Duration }{ {-time.Second, time.Second, -time.Second}, {-500 * time.Millisecond, time.Second, -time.Second}, {-499 * time.Millisecond, time.Second, 0}, {0, time.Second, 0}, {499 * time.Millisecond, time.Second, 0}, {500 * time.Millisecond, time.Second, time.Second}, {time.Second, time.Second, time.Second}, } for i, line := range data { ut.AssertEqualIndex(t, i, line.expected, Round(line.in, line.round)) } }
func TestGoroutinePriorityPoolWithPriority(t *testing.T) { t.Parallel() const MAX_PRIORITIES = 15 pool := NewGoroutinePriorityPool(1, NewCanceler()) logs := make(chan int) wg := sync.WaitGroup{} for i := 0; i < MAX_PRIORITIES; i++ { wg.Add(1) i := i go func() { pool.Schedule(int64(i), func() { logs <- i }, nil) wg.Done() }() } wg.Wait() var fail error go func() { defer close(logs) fail = pool.Wait() ut.ExpectEqual(t, nil, fail) }() doneJobs := make([]bool, MAX_PRIORITIES) // First job can be any, the rest must be in order. prio := <-logs doneJobs[prio] = true for prio := range logs { ut.AssertEqual(t, false, doneJobs[prio]) doneJobs[prio] = true // All higher priority jobs must be finished. for p := 0; p < prio; p++ { ut.AssertEqual(t, true, doneJobs[prio]) } } for p, d := range doneJobs { ut.AssertEqualIndex(t, p, true, d) } }
func TestSizeToString(t *testing.T) { t.Parallel() data := []struct { in int64 expected string }{ {0, "0b"}, {1, "1b"}, {1000, "1000b"}, {1023, "1023b"}, {1024, "1.00Kib"}, {1029, "1.00Kib"}, {1030, "1.01Kib"}, {10234, "9.99Kib"}, {10239, "10.00Kib"}, {10240, "10.0Kib"}, {1048575, "1024.0Kib"}, {1048576, "1.00Mib"}, } for i, line := range data { ut.AssertEqualIndex(t, i, line.expected, SizeToString(line.in)) } }
func TestGetImports(t *testing.T) { t.Parallel() data := []struct { in string pkg string imports []string }{ { "", "", nil, }, { "package foo", "foo", nil, }, { "package foo\nfunc bar() {}", "foo", nil, }, { "package foo\nconst i = 0", "foo", nil, }, { "const i = 0", "", nil, }, { "package foo\nimport \"bar\"", "foo", []string{"bar"}, }, { "package foo\nimport \"host/user/repo\"", "foo", []string{"host/user/repo"}, }, { "//\npackage foo\n//\n\nimport \"bar\"", "foo", []string{"bar"}, }, { "package foo\nimport \"bar\"\nconst i = 0", "foo", []string{"bar"}, }, { "package foo\nimport (\n\"bar\"\n)", "foo", []string{"bar"}, }, { "package foo\nimport (\n\"bér\"\n)", "foo", []string{"bér"}, }, { "package foo\nimport (\n\"b\u00e8r\"\n)", "foo", []string{"bèr"}, }, { // This is not legal Go. "package foo\nimport (\n\"bér\" \"ber\"\n)", "foo", []string{"bér", "ber"}, }, { "package foo\nimport (\n\"bar\"\n)\nconst i = 0", "foo", []string{"bar"}, }, { "package foo\nimport (\n\t\"bar\"\n\n\t// Yo\n\"baz\"\n )", "foo", []string{"bar", "baz"}, }, { "package foo\nimport (\n . \"bar\"\n)", "foo", []string{"bar"}, }, { "package foo\nimport (\n _ \"bar\"\n)", "foo", []string{"bar"}, }, { "package foo\nimport (\n fakename \"bar\"\n)", "foo", []string{"bar"}, }, } for i, line := range data { pkg, imports := getImports([]byte(line.in)) ut.AssertEqualIndex(t, i, line.pkg, pkg) ut.AssertEqualIndex(t, i, line.imports, imports) } }