github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/internal/task/expression_test.go (about)

     1  package task
     2  
     3  import (
     4  	"sort"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/anchore/syft/syft/cataloging/pkgcataloging"
    11  )
    12  
    13  func Test_newExpressionsFromSelectionRequest(t *testing.T) {
    14  	ts := []Task{
    15  		dummyTask("1", "t1"),
    16  		dummyTask("2", "t2"),
    17  		dummyTask("3", "t3"),
    18  		dummyTask("4", "t4"),
    19  		dummyTask("5"),
    20  		dummyTask("6"),
    21  	}
    22  
    23  	nc := newExpressionContext(ts)
    24  
    25  	var tests = []struct {
    26  		name           string
    27  		basis          []string
    28  		expressions    []string
    29  		expected       Expressions
    30  		expectedErrors []error
    31  	}{
    32  		{
    33  			name:        "empty input",
    34  			basis:       []string{},
    35  			expressions: []string{},
    36  			expected:    nil,
    37  		},
    38  		{
    39  			name:        "valid single set operation",
    40  			basis:       []string{"1"},
    41  			expressions: []string{},
    42  			expected: []Expression{
    43  				{Operation: SetOperation, Operand: "1"},
    44  			},
    45  		},
    46  		{
    47  			name:        "add operation",
    48  			basis:       []string{},
    49  			expressions: []string{"+4"},
    50  			expected: []Expression{
    51  				{Operation: AddOperation, Operand: "4"},
    52  			},
    53  		},
    54  		{
    55  			name:        "remove operation",
    56  			basis:       []string{},
    57  			expressions: []string{"-3"},
    58  			expected: []Expression{
    59  				{Operation: RemoveOperation, Operand: "3"},
    60  			},
    61  		},
    62  		{
    63  			name:        "select operation",
    64  			basis:       []string{},
    65  			expressions: []string{"t2"},
    66  			expected: []Expression{
    67  				{Operation: SubSelectOperation, Operand: "t2"},
    68  			},
    69  		},
    70  		{
    71  			name:        "mixed operations order",
    72  			basis:       []string{"1"},
    73  			expressions: []string{"+4", "-3", "t2"},
    74  			expected: []Expression{
    75  				// note they are sorted by operation
    76  				{Operation: SetOperation, Operand: "1"},
    77  				{Operation: SubSelectOperation, Operand: "t2"},
    78  				{Operation: RemoveOperation, Operand: "3"},
    79  				{Operation: AddOperation, Operand: "4"},
    80  			},
    81  		},
    82  		{
    83  			name:           "invalid token",
    84  			basis:          []string{"!1"},
    85  			expressions:    []string{},
    86  			expected:       nil,
    87  			expectedErrors: []error{ErrInvalidToken},
    88  		},
    89  		{
    90  			name:           "use + operator in basis",
    91  			basis:          []string{"+1"},
    92  			expressions:    []string{},
    93  			expected:       nil,
    94  			expectedErrors: []error{ErrInvalidToken},
    95  		},
    96  		{
    97  			name:           "use - operator in basis",
    98  			basis:          []string{"-1"},
    99  			expressions:    []string{},
   100  			expected:       nil,
   101  			expectedErrors: []error{ErrInvalidToken},
   102  		},
   103  		{
   104  			name:           "invalid name",
   105  			basis:          []string{},
   106  			expressions:    []string{"+t1"},
   107  			expected:       nil,
   108  			expectedErrors: []error{ErrTagsNotAllowed},
   109  		},
   110  		{
   111  			name:           "invalid tag",
   112  			basis:          []string{},
   113  			expressions:    []string{"1"},
   114  			expected:       nil,
   115  			expectedErrors: []error{ErrNamesNotAllowed},
   116  		},
   117  		{
   118  			name:           "invalid use of all",
   119  			basis:          []string{},
   120  			expressions:    []string{"all"},
   121  			expected:       nil,
   122  			expectedErrors: []error{ErrAllNotAllowed},
   123  		},
   124  		{
   125  			name:        "allow all operand",
   126  			basis:       []string{"all"},
   127  			expressions: []string{},
   128  			expected: []Expression{
   129  				// note they are sorted by operation
   130  				{Operation: SetOperation, Operand: "all"},
   131  			},
   132  		},
   133  	}
   134  
   135  	for _, tt := range tests {
   136  		t.Run(tt.name, func(t *testing.T) {
   137  
   138  			req := pkgcataloging.NewSelectionRequest().WithDefaults(tt.basis...).WithExpression(tt.expressions...)
   139  
   140  			result := newExpressionsFromSelectionRequest(nc, req)
   141  			if tt.expectedErrors != nil {
   142  				errs := result.Errors()
   143  				require.Len(t, errs, len(tt.expectedErrors))
   144  				for i, err := range tt.expectedErrors {
   145  					var target ErrInvalidExpression
   146  					require.ErrorAs(t, errs[i], &target)
   147  					assert.Equal(t, err, target.Err)
   148  				}
   149  			} else {
   150  				assert.Empty(t, result.Errors())
   151  				assert.Equal(t, tt.expected, result)
   152  			}
   153  		})
   154  	}
   155  }
   156  
   157  func Test_expressionNodes_sort(t *testing.T) {
   158  	tests := []struct {
   159  		name    string
   160  		subject Expressions
   161  		want    Expressions
   162  	}{
   163  		{
   164  			name: "sort operations but keep token order",
   165  			subject: []Expression{
   166  				{
   167  					Operation: AddOperation,
   168  					Operand:   "8",
   169  				},
   170  				{
   171  					Operation: AddOperation,
   172  					Operand:   "7",
   173  				},
   174  				{
   175  					Operation: RemoveOperation,
   176  					Operand:   "6",
   177  				},
   178  				{
   179  					Operation: RemoveOperation,
   180  					Operand:   "5",
   181  				},
   182  				{
   183  					Operation: SetOperation,
   184  					Operand:   "2",
   185  				},
   186  				{
   187  					Operation: SetOperation,
   188  					Operand:   "1",
   189  				},
   190  				{
   191  					Operation: SubSelectOperation,
   192  					Operand:   "4",
   193  				},
   194  				{
   195  					Operation: SubSelectOperation,
   196  					Operand:   "3",
   197  				},
   198  			},
   199  			want: []Expression{
   200  				{
   201  					Operation: SetOperation,
   202  					Operand:   "2",
   203  				},
   204  				{
   205  					Operation: SetOperation,
   206  					Operand:   "1",
   207  				},
   208  				{
   209  					Operation: SubSelectOperation,
   210  					Operand:   "4",
   211  				},
   212  				{
   213  					Operation: SubSelectOperation,
   214  					Operand:   "3",
   215  				},
   216  				{
   217  					Operation: RemoveOperation,
   218  					Operand:   "6",
   219  				},
   220  				{
   221  					Operation: RemoveOperation,
   222  					Operand:   "5",
   223  				},
   224  				{
   225  					Operation: AddOperation,
   226  					Operand:   "8",
   227  				},
   228  				{
   229  					Operation: AddOperation,
   230  					Operand:   "7",
   231  				},
   232  			},
   233  		},
   234  	}
   235  	for _, tt := range tests {
   236  		t.Run(tt.name, func(t *testing.T) {
   237  			s := tt.subject.Clone()
   238  			sort.Sort(s)
   239  			assert.Equal(t, tt.want, s)
   240  		})
   241  	}
   242  }