@@ -183,3 +183,103 @@ func TestDefaultRoute(t *testing.T) {
183183 })
184184 }
185185}
186+
187+ func TestValidateCycles (t * testing.T ) {
188+ tests := []struct {
189+ name string
190+ edges func () []Edge
191+ expectErr bool
192+ }{
193+ {
194+ name : "no cycles" ,
195+ edges : func () []Edge {
196+ nodeA := & dummyNode {name : "A" }
197+ nodeB := & dummyNode {name : "B" }
198+ return []Edge {
199+ {From : Start , To : nodeA },
200+ {From : nodeA , To : nodeB },
201+ }
202+ },
203+ expectErr : false ,
204+ },
205+ {
206+ name : "no cycles diamond graph" ,
207+ edges : func () []Edge {
208+ nodeA := & dummyNode {name : "A" }
209+ nodeB := & dummyNode {name : "B" }
210+ nodeC := & dummyNode {name : "C" }
211+ nodeD := & dummyNode {name : "D" }
212+ return []Edge {
213+ {From : Start , To : nodeA },
214+ {From : nodeA , To : nodeB },
215+ {From : nodeA , To : nodeC },
216+ {From : nodeB , To : nodeD },
217+ {From : nodeC , To : nodeD },
218+ }
219+ },
220+ expectErr : false ,
221+ },
222+ {
223+ name : "only conditional cycle" ,
224+ edges : func () []Edge {
225+ nodeA := & dummyNode {name : "A" }
226+ nodeB := & dummyNode {name : "B" }
227+ return []Edge {
228+ {From : Start , To : nodeA },
229+ {From : nodeA , To : nodeB },
230+ {From : nodeB , To : nodeA , Route : StringRoute ("back" )},
231+ }
232+ },
233+ expectErr : false ,
234+ },
235+ {
236+ name : "both conditional and unconditional cycles" ,
237+ edges : func () []Edge {
238+ nodeA := & dummyNode {name : "A" }
239+ nodeB := & dummyNode {name : "B" }
240+ nodeC := & dummyNode {name : "C" }
241+ nodeD := & dummyNode {name : "D" }
242+ return []Edge {
243+ {From : Start , To : nodeA },
244+ {From : nodeA , To : nodeB },
245+ {From : nodeB , To : nodeA , Route : StringRoute ("back" )},
246+ {From : Start , To : nodeC },
247+ {From : nodeC , To : nodeD },
248+ {From : nodeD , To : nodeC }, // Unconditional
249+ }
250+ },
251+ expectErr : true ,
252+ },
253+ {
254+ name : "cycle with default route" ,
255+ edges : func () []Edge {
256+ nodeA := & dummyNode {name : "A" }
257+ nodeB := & dummyNode {name : "B" }
258+ return []Edge {
259+ {From : Start , To : nodeA },
260+ {From : nodeA , To : nodeB },
261+ {From : nodeB , To : nodeA , Route : Default },
262+ }
263+ },
264+ expectErr : false ,
265+ },
266+ {
267+ name : "empty graph" ,
268+ edges : func () []Edge { return []Edge {} },
269+ expectErr : false ,
270+ },
271+ }
272+
273+ for _ , tc := range tests {
274+ t .Run (tc .name , func (t * testing.T ) {
275+ w := & Workflow {graph : newGraph (tc .edges ())}
276+
277+ err := validateCycles (w )
278+ if tc .expectErr && err == nil {
279+ t .Errorf ("expected error, got none" )
280+ } else if ! tc .expectErr && err != nil {
281+ t .Errorf ("expected no error, got %v" , err )
282+ }
283+ })
284+ }
285+ }
0 commit comments