OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package parser |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "testing" |
| 10 "time" |
| 11 |
| 12 . "github.com/luci/luci-go/common/testing/assertions" |
| 13 . "github.com/smartystreets/goconvey/convey" |
| 14 ) |
| 15 |
| 16 func TestValidation(t *testing.T) { |
| 17 good := map[string]Phrase{ |
| 18 "hello": {DepsStage{{Name: "hello"}}}, |
| 19 |
| 20 "A'": {DepsStage{{Name: "A'"}}}, |
| 21 |
| 22 "A' # comment!\n,{4}B&C": { |
| 23 DepsStage{{Name: "A'"}}, |
| 24 DepsStage{ |
| 25 {Name: "B", ShardCount: 4}, |
| 26 {Name: "C"}, |
| 27 }, |
| 28 }, |
| 29 |
| 30 "A,sub(B,C),D": { |
| 31 DepsStage{{Name: "A"}}, |
| 32 DepsStage{{Name: "sub", Substages: Phrase{ |
| 33 DepsStage{{Name: "B"}}, |
| 34 DepsStage{{Name: "C"}}, |
| 35 }}}, |
| 36 DepsStage{{Name: "D"}}, |
| 37 }, |
| 38 |
| 39 "[5]A": {DepsStage{ |
| 40 {Name: "A", AttemptNums: RangeSlice{{5, 0}}}}}, |
| 41 |
| 42 "A&B&C": {DepsStage{ |
| 43 {Name: "A"}, {Name: "B"}, {Name: "C"}, |
| 44 }}, |
| 45 |
| 46 "top(A,B)": { |
| 47 DepsStage{{Name: "top", Substages: Phrase{ |
| 48 DepsStage{{Name: "A"}}, |
| 49 DepsStage{{Name: "B"}}, |
| 50 }}}, |
| 51 }, |
| 52 |
| 53 "top(A,%1, B)": { |
| 54 DepsStage{{Name: "top", Substages: Phrase{ |
| 55 DepsStage{{Name: "A"}}, |
| 56 FailureStage(1), |
| 57 DepsStage{{Name: "B"}}, |
| 58 }}}, |
| 59 }, |
| 60 |
| 61 "cool(@5,=10<20)": { |
| 62 DepsStage{{Name: "cool", Substages: Phrase{ |
| 63 StallStage(time.Second * 5), |
| 64 &ReturnStage{10, time.Second * 20}, |
| 65 }}}, |
| 66 }, |
| 67 |
| 68 "[1-3, 2-5]cool": {DepsStage{ |
| 69 {Name: "cool", AttemptNums: RangeSlice{{1, 3}, {2, 5}}}}
}, |
| 70 |
| 71 "cool+4(nerd(%80))": {DepsStage{ |
| 72 {Name: "cool", Retries: 4, Substages: Phrase{ |
| 73 DepsStage{{Name: "nerd", Substages: Phrase{ |
| 74 FailureStage(80), |
| 75 }}}, |
| 76 }}, |
| 77 }}, |
| 78 |
| 79 "[1,2-3]cool": {DepsStage{ |
| 80 {Name: "cool", AttemptNums: RangeSlice{{1, 0}, {2, 3}}}, |
| 81 }}, |
| 82 } |
| 83 |
| 84 bad := map[string]string{ |
| 85 "": "empty phrase", |
| 86 "&wat": "expected dependency", |
| 87 "=10,wat": `extra: ",wat"`, |
| 88 "=10,=20": `extra: ",=20"`, |
| 89 "wat&%10": `extra: "&%10"`, |
| 90 "100": "expected phrase", |
| 91 "A10": `extra: "10"`, |
| 92 ",something": "expected stage", |
| 93 "A.A'&&": `extra: ".A'&&"`, |
| 94 "A{5}": `extra: "{5}"`, |
| 95 "(5)": "expected phrase", |
| 96 "=cow": "expected number", |
| 97 "=10<neet": "expected number", |
| 98 "@moo": "expected number", |
| 99 "%moo": "expected number", |
| 100 "what&&": `extra: "&&"`, |
| 101 "{no}cats": "expected phrase", |
| 102 "{10,moo}": "expected phrase", |
| 103 "[2-1]cool": `invalid range "2-1": lo >= hi`, |
| 104 "[2-bob]cool": "expected number", |
| 105 "[bob]cool": "expected number", |
| 106 "cool+nope": "expected number", |
| 107 "cool(@)": "expected number", |
| 108 "cool!pop": `extra: "!pop"`, |
| 109 "cool+0": "zero value not acceptable", |
| 110 "[0]cool": "zero value not acceptable", |
| 111 "[0-2]cool": "zero value not acceptable", |
| 112 } |
| 113 |
| 114 Convey("validPhrase", t, func() { |
| 115 Convey("good", func() { |
| 116 for in, p := range good { |
| 117 Convey(fmt.Sprintf("%q", in), func() { |
| 118 cleaned := CleanPhrase(in) |
| 119 out, err := ParsePhrase(cleaned) |
| 120 So(err, ShouldBeNil) |
| 121 So(out, ShouldResembleV, p) |
| 122 So(out.String(), ShouldEqual, cleaned) |
| 123 }) |
| 124 } |
| 125 }) |
| 126 Convey("bad", func() { |
| 127 for in, expect := range bad { |
| 128 Convey(fmt.Sprintf("%q", in), func() { |
| 129 _, err := ParsePhrase(CleanPhrase(in)) |
| 130 So(err, ShouldErrLike, expect) |
| 131 }) |
| 132 } |
| 133 }) |
| 134 }) |
| 135 } |
OLD | NEW |