aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/aflow/loop_test.go
blob: df869cb273aba293e4835cc8a828d53345c67fcf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2026 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package aflow

import (
	"testing"
)

func TestDoWhile(t *testing.T) {
	type inputs struct {
		Bug string
	}
	type outputs struct {
		Diff string
	}
	type patchArgs struct {
		Bug       string
		Diff      string
		TestError string
	}
	type patchResults struct {
		Patch string
	}
	type testArgs struct {
		Patch string
	}
	type testResults struct {
		Diff      string
		TestError string
	}
	iter := 0
	testFlow[inputs, outputs](t, map[string]any{"Bug": "bug"}, map[string]any{"Diff": "diff"},
		&DoWhile{
			Do: Pipeline(
				NewFuncAction("patch-generator", func(ctx *Context, args patchArgs) (patchResults, error) {
					iter++
					if iter <= 2 {
						return patchResults{"bad"}, nil
					}
					return patchResults{"good"}, nil
				}),
				NewFuncAction("patch-tester", func(ctx *Context, args testArgs) (testResults, error) {
					if args.Patch == "bad" {
						return testResults{TestError: "error"}, nil
					}
					return testResults{Diff: "diff"}, nil
				}),
			),
			While:         "TestError",
			MaxIterations: 10,
		},
		nil,
		nil,
	)
}

func TestDoWhileErrors(t *testing.T) {
	testRegistrationError[struct{}, struct{}](t,
		"flow test: action body: no input Missing, available inputs: []",
		&Flow{Root: &DoWhile{
			Do: NewFuncAction("body", func(ctx *Context, args struct {
				Missing string
			}) (struct{}, error) {
				return struct{}{}, nil
			}),
			While:         "Condition",
			MaxIterations: 10,
		}})

	testRegistrationError[struct{ Input string }, struct{}](t,
		"flow test: action DoWhile: While must not be empty",
		&Flow{Root: &DoWhile{
			Do: NewFuncAction("body", func(ctx *Context, args struct {
				Input string
			}) (struct{}, error) {
				return struct{}{}, nil
			}),
			MaxIterations: 10,
		}})

	type output struct {
		Output1 string
		Output2 string
	}
	testRegistrationError[struct{}, struct{}](t,
		"flow test: action body: output Output2 is unused",
		&Flow{Root: &DoWhile{
			Do: NewFuncAction("body", func(ctx *Context, args struct{}) (output, error) {
				return output{}, nil
			}),
			While:         "Output1",
			MaxIterations: 10,
		}})

	testRegistrationError[struct{}, struct{}](t,
		"flow test: action DoWhile: bad MaxIterations value 0, should be within [1, 1000]",
		&Flow{Root: &DoWhile{
			Do: NewFuncAction("body", func(ctx *Context, args struct{}) (output, error) {
				return output{}, nil
			}),
			While: "Output1",
		}})
}

func TestDoWhileMaxIters(t *testing.T) {
	type actionResults struct {
		Error string
	}
	testFlow[struct{}, struct{}](t, nil, "DoWhile loop is going in cycles for 3 iterations",
		&DoWhile{
			Do: NewFuncAction("nop", func(ctx *Context, args struct{}) (actionResults, error) {
				return actionResults{"failed"}, nil
			}),
			While:         "Error",
			MaxIterations: 3,
		},
		nil,
		nil,
	)
}