github.com/rajeev159/opa@v0.45.0/ast/compare_test.go (about)

     1  // Copyright 2016 The OPA Authors.  All rights reserved.
     2  // Use of this source code is governed by an Apache2
     3  // license that can be found in the LICENSE file.
     4  
     5  package ast
     6  
     7  import (
     8  	"testing"
     9  )
    10  
    11  func TestCompare(t *testing.T) {
    12  
    13  	// Many of the comparison cases are covered by existing equality tests. Here
    14  	// we cover edge cases.
    15  	tests := []struct {
    16  		a        string
    17  		b        string
    18  		expected int
    19  	}{
    20  		// Comparisons to Go nil. Everything is greater than nil and nil is equal to nil
    21  		{"null", "", 1},
    22  		{"", "null", -1},
    23  		{"", "", 0},
    24  
    25  		// Booleans
    26  		{"false", "true", -1},
    27  		{"true", "false", 1},
    28  
    29  		// Numbers
    30  		{"0", "1", -1},
    31  		{"1", "0", 1},
    32  		{"0", "0", 0},
    33  		{"0", "1.5", -1},
    34  		{"1.5", "0", 1},
    35  		{"123456789123456789123", "123456789123456789123", 0},
    36  		{"123456789123456789123", "123456789123456789122", 1},
    37  		{"123456789123456789122", "123456789123456789123", -1},
    38  		{"123456789123456789123.5", "123456789123456789123.5", 0},
    39  		{"123456789123456789123.5", "123456789123456789122.5", 1},
    40  		{"123456789123456789122.5", "123456789123456789123.5", -1},
    41  		{"630E-840354372", "0", 0},
    42  
    43  		// Object comparisons are consistent
    44  		{`{1: 2, 3: 4}`, `{4: 3, 1: 2}`, -1},
    45  		{`{1: 2, 3: 4}`, `{1: 2, 4: 3}`, -1},
    46  		{`{1: 2, 3: 4}`, `{1: 2, 3: 5}`, -1},
    47  		{`{1: 2, 3: 4}`, `{1: 2, 3: 4, 5: 6}`, -1},
    48  		{`{1: 2, 3: 4, 5: 6}`, `{1: 2, 3: 4}`, 1},
    49  
    50  		// Comprehensions
    51  		{`[null | true]`, `[false | null]`, -1},
    52  		{`{null | true}`, `{false | null}`, -1},
    53  		{`{"abc": null | true}`, `{"cba": false | null}`, -1},
    54  
    55  		// Expressions
    56  		{`a = b`, `b = a`, -1},
    57  		{`b = a`, `not a = b`, -1},
    58  		{`a = b`, `x`, 1},
    59  		{`a = b`, `a = b with input.foo as bar`, -1},
    60  		{`a = b with input.foo as bar`, `a = b`, 1},
    61  		{`a = b with input.foo as bar`, `a = b with input.foo.bar.baz as qux`, -1},
    62  		{`a = b with input.foo as bar`, `a = b with input.foo as bar with input.baz as qux`, -1},
    63  
    64  		// Body
    65  		{`a = b`, `a = b; b = a`, -1},
    66  		{`a = b; b = a`, `a = b`, 1},
    67  	}
    68  	for _, tc := range tests {
    69  		var a, b interface{}
    70  		if len(tc.a) > 0 {
    71  			a = MustParseStatement(tc.a)
    72  		}
    73  		if len(tc.b) > 0 {
    74  			b = MustParseStatement(tc.b)
    75  		}
    76  		result := Compare(a, b)
    77  		if tc.expected != result {
    78  			t.Errorf("Expected %v.Compare(%v) == %v but got %v", a, b, tc.expected, result)
    79  		}
    80  	}
    81  }
    82  
    83  func TestCompareModule(t *testing.T) {
    84  	a := MustParseModule(`package a.b.c`)
    85  	b := MustParseModule(`package a.b.d`)
    86  	result := Compare(a, b)
    87  
    88  	if result != -1 {
    89  		t.Errorf("Expected %v to be less than %v but got: %v", a, b, result)
    90  	}
    91  
    92  	a = MustParseModule(`package a.b.c
    93  
    94  import input.x.y`)
    95  	b = MustParseModule(`package a.b.c
    96  
    97  import input.x.z`)
    98  	result = Compare(a, b)
    99  
   100  	if result != -1 {
   101  		t.Errorf("Expected %v to be less than %v but got: %v", a, b, result)
   102  	}
   103  
   104  	var err error
   105  
   106  	a, err = ParseModuleWithOpts("test.rego", `package a
   107  
   108  # METADATA
   109  # scope: rule
   110  # schemas:
   111  # - input: schema.a
   112  p := 7`, ParserOptions{ProcessAnnotation: true})
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  
   117  	b, err = ParseModuleWithOpts("test.rego", `package a
   118  
   119  # METADATA
   120  # scope: rule
   121  # schemas:
   122  # - input: schema.b
   123  p := 7`, ParserOptions{ProcessAnnotation: true})
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  
   128  	result = Compare(a, b)
   129  
   130  	if result != -1 {
   131  		t.Errorf("Expected %v to be less than %v but got: %v", a, b, result)
   132  	}
   133  }
   134  
   135  func TestCompareAnnotations(t *testing.T) {
   136  
   137  	tests := []struct {
   138  		note string
   139  		a    string
   140  		b    string
   141  		exp  int
   142  	}{
   143  		{
   144  			note: "same",
   145  			a: `
   146  # METADATA
   147  # scope: a`,
   148  			b: `
   149  # METADATA
   150  # scope: a`,
   151  			exp: 0,
   152  		},
   153  		{
   154  			note: "unknown scope",
   155  			a: `
   156  # METADATA
   157  # scope: rule`,
   158  			b: `
   159  # METADATA
   160  # scope: a`,
   161  			exp: 1,
   162  		},
   163  		{
   164  			note: "unknown scope - less than",
   165  			a: `
   166  # METADATA
   167  # scope: a`,
   168  			b: `
   169  # METADATA
   170  # scope: rule`,
   171  			exp: -1,
   172  		},
   173  		{
   174  			note: "unknown scope - greater than - lexigraphical",
   175  			a: `
   176  # METADATA
   177  # scope: b`,
   178  			b: `
   179  # METADATA
   180  # scope: a`,
   181  			exp: 1,
   182  		},
   183  		{
   184  			note: "unknown scope - less than - lexigraphical",
   185  			a: `
   186  # METADATA
   187  # scope: b`,
   188  			b: `
   189  # METADATA
   190  # scope: c`,
   191  			exp: -1,
   192  		},
   193  		{
   194  			note: "schema",
   195  			a: `
   196  # METADATA
   197  # scope: rule
   198  # schemas:
   199  # - input: schema`,
   200  			b: `
   201  # METADATA
   202  # scope: rule
   203  # schemas:
   204  # - input: schema`,
   205  			exp: 0,
   206  		},
   207  		{
   208  			note: "schema - less than",
   209  			a: `
   210  # METADATA
   211  # scope: rule
   212  # schemas:
   213  # - input.a: schema`,
   214  			b: `
   215  # METADATA
   216  # scope: rule
   217  # schemas:
   218  # - input.b: schema`,
   219  			exp: -1,
   220  		},
   221  		{
   222  			note: "schema - greater than",
   223  			a: `
   224  # METADATA
   225  # scope: rule
   226  # schemas:
   227  # - input.b: schema`,
   228  			b: `
   229  # METADATA
   230  # scope: rule
   231  # schemas:
   232  # - input.a: schema`,
   233  			exp: 1,
   234  		},
   235  		{
   236  			note: "schema - less than (fewer)",
   237  			a: `
   238  # METADATA
   239  # scope: rule
   240  # schemas:
   241  # - input.a: schema`,
   242  			b: `
   243  # METADATA
   244  # scope: rule
   245  # schemas:
   246  # - input.a: schema
   247  # - input.b: schema`,
   248  			exp: -1,
   249  		},
   250  		{
   251  			note: "schema - greater than (more)",
   252  			a: `
   253  # METADATA
   254  # scope: rule
   255  # schemas:
   256  # - input.a: schema
   257  # - input.b: schema`,
   258  			b: `
   259  # METADATA
   260  # scope: rule
   261  # schemas:
   262  # - input.a: schema`,
   263  			exp: 1,
   264  		},
   265  		{
   266  			note: "schema - less than - lexigraphical",
   267  			a: `
   268  # METADATA
   269  # scope: rule
   270  # schemas:
   271  # - input: schema.a`,
   272  			b: `
   273  # METADATA
   274  # scope: rule
   275  # schemas:
   276  # - input: schema.b`,
   277  			exp: -1,
   278  		},
   279  		{
   280  			note: "schema - greater than - lexigraphical",
   281  			a: `
   282  # METADATA
   283  # scope: rule
   284  # schemas:
   285  # - input: schema.c`,
   286  			b: `
   287  # METADATA
   288  # scope: rule
   289  # schemas:
   290  # - input: schema.b`,
   291  			exp: 1,
   292  		},
   293  		{
   294  			note: "definition",
   295  			a: `
   296  # METADATA
   297  # schemas:
   298  # - input: {"type": "string"}`,
   299  			b: `
   300  # METADATA
   301  # schemas:
   302  # - input: {"type": "string"}`,
   303  		},
   304  		{
   305  			note: "definition - less than schema",
   306  			a: `
   307  # METADATA
   308  # schemas:
   309  # - input: {"type": "string"}`,
   310  			b: `
   311  # METADATA
   312  # schemas:
   313  # - input: schema.a`,
   314  			exp: -1,
   315  		},
   316  		{
   317  			note: "schema - greater than definition",
   318  			a: `
   319  # METADATA
   320  # schemas:
   321  # - input: schema.a`,
   322  			b: `
   323  # METADATA
   324  # schemas:
   325  # - input: {"type": "string"}`,
   326  			exp: 1,
   327  		},
   328  		{
   329  			note: "title",
   330  			a: `
   331  # METADATA
   332  # title: a`,
   333  			b: `
   334  # METADATA
   335  # title: a`,
   336  			exp: 0,
   337  		},
   338  		{
   339  			note: "title - less than",
   340  			a: `
   341  # METADATA
   342  # title: a`,
   343  			b: `
   344  # METADATA
   345  # title: b`,
   346  			exp: -1,
   347  		},
   348  		{
   349  			note: "title - greater than",
   350  			a: `
   351  # METADATA
   352  # title: b`,
   353  			b: `
   354  # METADATA
   355  # title: a`,
   356  			exp: 1,
   357  		},
   358  		{
   359  			note: "description",
   360  			a: `
   361  # METADATA
   362  # description: a`,
   363  			b: `
   364  # METADATA
   365  # description: a`,
   366  			exp: 0,
   367  		},
   368  		{
   369  			note: "description - less than",
   370  			a: `
   371  # METADATA
   372  # description: a`,
   373  			b: `
   374  # METADATA
   375  # description: b`,
   376  			exp: -1,
   377  		},
   378  		{
   379  			note: "description - greater than",
   380  			a: `
   381  # METADATA
   382  # description: b`,
   383  			b: `
   384  # METADATA
   385  # description: a`,
   386  			exp: 1,
   387  		},
   388  		{
   389  			note: "authors",
   390  			a: `
   391  # METADATA
   392  # authors: 
   393  # - John Doe
   394  # - Jane Doe`,
   395  			b: `
   396  # METADATA
   397  # authors: 
   398  # - John Doe
   399  # - Jane Doe`,
   400  			exp: 0,
   401  		},
   402  		{
   403  			note: "authors - less than",
   404  			a: `
   405  # METADATA
   406  # authors: 
   407  # - Jane Doe
   408  # - John Doe
   409  `,
   410  			b: `
   411  # METADATA
   412  # authors: 
   413  # - John Doe
   414  # - Jane Doe`,
   415  			exp: -1,
   416  		},
   417  		{
   418  			note: "authors - greater than",
   419  			a: `
   420  # METADATA
   421  # authors: 
   422  # - John Doe
   423  # - Jane Doe`,
   424  			b: `
   425  # METADATA
   426  # authors: 
   427  # - Jane Doe
   428  # - John Doe`,
   429  			exp: 1,
   430  		},
   431  		{
   432  			note: "authors - less than (fewer)",
   433  			a: `
   434  # METADATA
   435  # scope: rule
   436  # authors:
   437  # - John Doe`,
   438  			b: `
   439  # METADATA
   440  # scope: rule
   441  # authors:
   442  # - John Doe
   443  # - Jane Doe`,
   444  			exp: -1,
   445  		},
   446  		{
   447  			note: "authors - greater than (more)",
   448  			a: `
   449  # METADATA
   450  # scope: rule
   451  # authors:
   452  # - John Doe
   453  # - Jane Doe`,
   454  			b: `
   455  # METADATA
   456  # scope: rule
   457  # authors:
   458  # - John Doe`,
   459  			exp: 1,
   460  		},
   461  		{
   462  			note: "authors - less than (email)",
   463  			a: `
   464  # METADATA
   465  # authors: 
   466  # - John Doe <a@example.com>`,
   467  			b: `
   468  # METADATA
   469  # authors: 
   470  # - John Doe <b@example.com>`,
   471  			exp: -1,
   472  		},
   473  		{
   474  			note: "authors - greater than (email)",
   475  			a: `
   476  # METADATA
   477  # authors: 
   478  # - John Doe <b@example.com>`,
   479  			b: `
   480  # METADATA
   481  # authors: 
   482  # - John Doe <a@example.com>`,
   483  			exp: 1,
   484  		},
   485  		{
   486  			note: "organizations",
   487  			a: `
   488  # METADATA
   489  # organizations: 
   490  # - a
   491  # - b`,
   492  			b: `
   493  # METADATA
   494  # organizations: 
   495  # - a
   496  # - b`,
   497  			exp: 0,
   498  		},
   499  		{
   500  			note: "organizations - less than",
   501  			a: `
   502  # METADATA
   503  # organizations: 
   504  # - a
   505  # - b`,
   506  			b: `
   507  # METADATA
   508  # organizations: 
   509  # - c
   510  # - d`,
   511  			exp: -1,
   512  		},
   513  		{
   514  			note: "organizations - greater than",
   515  			a: `
   516  # METADATA
   517  # organizations: 
   518  # - c
   519  # - d`,
   520  			b: `
   521  # METADATA
   522  # organizations: 
   523  # - a
   524  # - b`,
   525  			exp: 1,
   526  		},
   527  		{
   528  			note: "organizations - less than (fewer)",
   529  			a: `
   530  # METADATA
   531  # scope: rule
   532  # organizations:
   533  # - a`,
   534  			b: `
   535  # METADATA
   536  # scope: rule
   537  # organizations:
   538  # - a
   539  # - b`,
   540  			exp: -1,
   541  		},
   542  		{
   543  			note: "organizations - greater than (more)",
   544  			a: `
   545  # METADATA
   546  # scope: rule
   547  # organizations:
   548  # - a
   549  # - b`,
   550  			b: `
   551  # METADATA
   552  # scope: rule
   553  # organizations:
   554  # - a`,
   555  			exp: 1,
   556  		},
   557  		{
   558  			note: "related_resources",
   559  			a: `
   560  # METADATA
   561  # related_resources: 
   562  # - https://a.example.com
   563  # - 
   564  #  ref: https://b.example.com
   565  #  description: foo bar`,
   566  			b: `
   567  # METADATA
   568  # related_resources: 
   569  # - https://a.example.com
   570  # - 
   571  #  ref: https://b.example.com
   572  #  description: foo bar`,
   573  			exp: 0,
   574  		},
   575  		{
   576  			note: "related_resources - less than",
   577  			a: `
   578  # METADATA
   579  # related_resources: 
   580  # - https://a.example.com
   581  # - https://b.example.com`,
   582  			b: `
   583  # METADATA
   584  # related_resources: 
   585  # - https://b.example.com
   586  # - https://c.example.com`,
   587  			exp: -1,
   588  		},
   589  		{
   590  			note: "related_resources - greater than",
   591  			a: `
   592  # METADATA
   593  # related_resources: 
   594  # - https://b.example.com
   595  # - https://c.example.com`,
   596  			b: `
   597  # METADATA
   598  # related_resources: 
   599  # - https://a.example.com
   600  # - https://b.example.com`,
   601  			exp: 1,
   602  		},
   603  		{
   604  			note: "related_resources - less than (fewer)",
   605  			a: `
   606  # METADATA
   607  # scope: rule
   608  # organizations:
   609  # - https://a.example.com`,
   610  			b: `
   611  # METADATA
   612  # scope: rule
   613  # organizations:
   614  # - https://a.example.com
   615  # - https://b.example.com`,
   616  			exp: -1,
   617  		},
   618  		{
   619  			note: "related_resources - greater than (more)",
   620  			a: `
   621  # METADATA
   622  # scope: rule
   623  # organizations:
   624  # - https://a.example.com
   625  # - https://b.example.com`,
   626  			b: `
   627  # METADATA
   628  # scope: rule
   629  # organizations:
   630  # - https://a.example.com`,
   631  			exp: 1,
   632  		},
   633  		{
   634  			note: "related_resources - less than (description)",
   635  			a: `
   636  # METADATA
   637  # related_resources:
   638  # -
   639  #  ref: https://example.com
   640  #  description: a`,
   641  			b: `
   642  # METADATA
   643  # related_resources:
   644  # -
   645  #  ref: https://example.com
   646  #  description: b`,
   647  			exp: -1,
   648  		},
   649  		{
   650  			note: "related_resources - greater than (description)",
   651  			a: `
   652  # METADATA
   653  # related_resources:
   654  # -
   655  #  ref: https://example.com
   656  #  description: b`,
   657  			b: `
   658  # METADATA
   659  # related_resources:
   660  # -
   661  #  ref: https://example.com
   662  #  description: a`,
   663  			exp: 1,
   664  		},
   665  		{
   666  			note: "custom",
   667  			a: `
   668  # METADATA
   669  # custom: 
   670  #  a: 1
   671  #  b: true
   672  #  c:
   673  #  d:
   674  #  - 1
   675  #  - 2
   676  #  e:
   677  #   i: 1
   678  #   j: 2`,
   679  			b: `
   680  # METADATA
   681  # custom: 
   682  #  a: 1
   683  #  b: true
   684  #  c:
   685  #  d:
   686  #  - 1
   687  #  - 2
   688  #  e:
   689  #   i: 1
   690  #   j: 2`,
   691  			exp: 0,
   692  		},
   693  		{
   694  			note: "custom - less than",
   695  			a: `
   696  # METADATA
   697  # custom: 
   698  #  a: 1`,
   699  			b: `
   700  # METADATA
   701  # custom: 
   702  #  b: 1`,
   703  			exp: -1,
   704  		},
   705  		{
   706  			note: "custom - greater than",
   707  			a: `
   708  # METADATA
   709  # custom: 
   710  #  b: 1`,
   711  			b: `
   712  # METADATA
   713  # custom: 
   714  #  a: 1`,
   715  			exp: 1,
   716  		},
   717  		{
   718  			note: "custom - less than (value)",
   719  			a: `
   720  # METADATA
   721  # custom: 
   722  #  a: 1`,
   723  			b: `
   724  # METADATA
   725  # custom: 
   726  #  a: 2`,
   727  			exp: -1,
   728  		},
   729  		{
   730  			note: "custom - greater than (value)",
   731  			a: `
   732  # METADATA
   733  # custom: 
   734  #  a: 2`,
   735  			b: `
   736  # METADATA
   737  # custom: 
   738  #  a: 1`,
   739  			exp: 1,
   740  		},
   741  		{
   742  			note: "custom - less than (fewer)",
   743  			a: `
   744  # METADATA
   745  # custom: 
   746  #  a: 1`,
   747  			b: `
   748  # METADATA
   749  # custom: 
   750  #  a: 1
   751  #  b: 2`,
   752  			exp: -1,
   753  		},
   754  		{
   755  			note: "custom - greater than (more)",
   756  			a: `
   757  # METADATA
   758  # custom: 
   759  #  a: 1
   760  #  b: 2`,
   761  			b: `
   762  # METADATA
   763  # custom: 
   764  #  a: 1`,
   765  			exp: 1,
   766  		},
   767  	}
   768  
   769  	for _, tc := range tests {
   770  		t.Run(tc.note, func(t *testing.T) {
   771  			stmts, _, err := ParseStatementsWithOpts("test.rego", tc.a, ParserOptions{ProcessAnnotation: true})
   772  			if err != nil {
   773  				t.Fatal(err)
   774  			}
   775  			a := stmts[0].(*Annotations)
   776  			stmts, _, err = ParseStatementsWithOpts("test.rego", tc.b, ParserOptions{ProcessAnnotation: true})
   777  			if err != nil {
   778  				t.Fatal(err)
   779  			}
   780  			b := stmts[0].(*Annotations)
   781  			result := a.Compare(b)
   782  			if result != tc.exp {
   783  				t.Fatalf("Expected %d but got %v for %v and %v", tc.exp, result, a, b)
   784  			}
   785  		})
   786  	}
   787  }