github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/assertion_parser_test.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func testLexer(t *testing.T, name string, s string, expected []Token) {
    14  	lexer := NewLexer(s)
    15  	i := 0
    16  	for {
    17  		tok := lexer.Get()
    18  		if i >= len(expected) {
    19  			t.Errorf("%s, unexpected token %d [T%v: '%v']", name, i, tok.Typ, string(tok.value))
    20  			break
    21  		}
    22  		if !tok.Eq(expected[i]) {
    23  			t.Errorf("%s, token %d: [T%v: '%v'] != [T%v: '%v']",
    24  				name, i, tok.Typ, string(tok.value), expected[i].Typ, string(expected[i].value))
    25  		}
    26  		if tok.Typ == EOF {
    27  			break
    28  		}
    29  		i++
    30  	}
    31  }
    32  
    33  func TestLexer1(t *testing.T) {
    34  	s := "http://foo.com && http://bar.com"
    35  	expected := []Token{
    36  		{URL, []byte("http://foo.com")},
    37  		{AND, []byte("&&")},
    38  		{URL, []byte("http://bar.com")},
    39  		{EOF, []byte{}},
    40  	}
    41  	testLexer(t, "test1", s, expected)
    42  }
    43  
    44  func TestLexer2(t *testing.T) {
    45  	s := "   (   a    && b          ) || (  c && d && e )   "
    46  	expected := []Token{
    47  		{LPAREN, []byte("(")},
    48  		{URL, []byte("a")},
    49  		{AND, []byte("&&")},
    50  		{URL, []byte("b")},
    51  		{RPAREN, []byte(")")},
    52  		{OR, []byte("||")},
    53  		{LPAREN, []byte("(")},
    54  		{URL, []byte("c")},
    55  		{AND, []byte("&&")},
    56  		{URL, []byte("d")},
    57  		{AND, []byte("&&")},
    58  		{URL, []byte("e")},
    59  		{RPAREN, []byte(")")},
    60  		{EOF, []byte{}},
    61  	}
    62  	testLexer(t, "test2", s, expected)
    63  }
    64  
    65  func TestLexer3(t *testing.T) {
    66  	s := "aa && |bb"
    67  	expected := []Token{
    68  		{URL, []byte("aa")},
    69  		{AND, []byte("&&")},
    70  		{ERROR, []byte("|bb")},
    71  		{EOF, []byte{}},
    72  	}
    73  	testLexer(t, "test3", s, expected)
    74  }
    75  
    76  func TestLexerSquareBrackets(t *testing.T) {
    77  	s := "michal,[michal@zapu.net]@email"
    78  	expected := []Token{
    79  		{URL, []byte("michal")},
    80  		{OR, []byte(",")},
    81  		{URL, []byte("[michal@zapu.net]@email")},
    82  		{EOF, []byte{}},
    83  	}
    84  	testLexer(t, "square brackets", s, expected)
    85  }
    86  
    87  func TestLexerEmailInvalidParentheses(t *testing.T) {
    88  	// Rejected proposal for round brackets, but make sure
    89  	// there is expected way in which it is parsed.
    90  
    91  	s := "michal,(michal@zapu.net)@email"
    92  	expected := []Token{
    93  		{URL, []byte("michal")},
    94  		{OR, []byte(",")},
    95  		{LPAREN, []byte("(")},
    96  		{URL, []byte("michal@zapu.net")},
    97  		{RPAREN, []byte(")")},
    98  		{URL, []byte("@email")},
    99  		{EOF, []byte{}},
   100  	}
   101  	testLexer(t, "round brackets", s, expected)
   102  
   103  	s = "twitter://alice&&(alice@keybasers.de)@email"
   104  	expected = []Token{
   105  		{URL, []byte("twitter://alice")},
   106  		{AND, []byte("&&")},
   107  		{LPAREN, []byte("(")},
   108  		{URL, []byte("alice@keybasers.de")},
   109  		{RPAREN, []byte(")")},
   110  		{URL, []byte("@email")},
   111  		{EOF, []byte{}},
   112  	}
   113  	testLexer(t, "round brackets", s, expected)
   114  }
   115  
   116  func TestLexerEmailPlusSign(t *testing.T) {
   117  	s := "twitter://alice&&[a.li.c+e@keybasers.de]@email"
   118  	expected := []Token{
   119  		{URL, []byte("twitter://alice")},
   120  		{AND, []byte("&&")},
   121  		{URL, []byte("[a.li.c+e@keybasers.de]@email")},
   122  		{EOF, []byte{}},
   123  	}
   124  	testLexer(t, "square brackets 1", s, expected)
   125  
   126  	s = "alice@twitter||email:[a.li.c+e@keybasers.de]"
   127  	expected = []Token{
   128  		{URL, []byte("alice@twitter")},
   129  		{OR, []byte("||")},
   130  		{URL, []byte("email:[a.li.c+e@keybasers.de]")},
   131  		{EOF, []byte{}},
   132  	}
   133  	testLexer(t, "square brackets 2", s, expected)
   134  
   135  	s = "alice@twitter||email://[a.li.c+e@keybasers.de]"
   136  	expected = []Token{
   137  		{URL, []byte("alice@twitter")},
   138  		{OR, []byte("||")},
   139  		{URL, []byte("email://[a.li.c+e@keybasers.de]")},
   140  		{EOF, []byte{}},
   141  	}
   142  	testLexer(t, "square brackets 3", s, expected)
   143  
   144  	// This is not a valid email, but not caught at the lexer stage,
   145  	// it's still supposed to generate URL token.
   146  	s = "twitter:ae,email:[a,e@keybasers.de]"
   147  	expected = []Token{
   148  		{URL, []byte("twitter:ae")},
   149  		{OR, []byte(",")},
   150  		{URL, []byte("email:[a,e@keybasers.de]")},
   151  		{EOF, []byte{}},
   152  	}
   153  	testLexer(t, "square brackets 4", s, expected)
   154  
   155  	// Same here:
   156  	s = "email:[],email://[]"
   157  	expected = []Token{
   158  		{URL, []byte("email:[]")},
   159  		{OR, []byte(",")},
   160  		{URL, []byte("email://[]")},
   161  		{EOF, []byte{}},
   162  	}
   163  	testLexer(t, "square brackets 5", s, expected)
   164  
   165  	// Weirdness
   166  	s = "[michal]@[keybase]"
   167  	expected = []Token{
   168  		{URL, []byte("[michal]@")},
   169  		{ERROR, []byte("[keybase]")},
   170  		{EOF, []byte{}},
   171  	}
   172  	testLexer(t, "square brackets 6", s, expected)
   173  }
   174  
   175  func TestParser1(t *testing.T) {
   176  	inp := "  aa ||   bb   && cc ||\n dd ||\n ee && ff || gg && (hh ||\nii)"
   177  	outp := "aa,bb+cc,dd,ee+ff,gg+(hh,ii)"
   178  	expr, err := AssertionParse(testAssertionContext{}, inp)
   179  	if err != nil {
   180  		t.Error(err)
   181  	} else if expr.String() != outp {
   182  		t.Errorf("Wrong parse result: %s v %s", expr.String(), outp)
   183  	}
   184  }
   185  
   186  func TestParser2(t *testing.T) {
   187  	inp := "  web://a.aa ||   http://b.bb   && dns://c.cc ||\n dd ||\n pgp:ee && reddit:foo || twitter:goo && (https:h.in ||\ndns:i.co)"
   188  	outp := "a.aa@web,b.bb@http+c.cc@dns,dd,ee@pgp+foo@reddit,goo@twitter+(h.in@https,i.co@dns)"
   189  	expr, err := AssertionParse(testAssertionContext{}, inp)
   190  	if err != nil {
   191  		t.Error(err)
   192  	} else if expr.String() != outp {
   193  		t.Errorf("Wrong parse result: %s v %s", expr.String(), outp)
   194  	}
   195  }
   196  
   197  func TestNormalization(t *testing.T) {
   198  	// Test moved to externals/ since it requires knowledge of social networks
   199  }
   200  
   201  type Pair struct {
   202  	k, v string
   203  }
   204  
   205  func TestParserFail1(t *testing.T) {
   206  	bads := []Pair{
   207  		{"aa ||", "Unexpected EOF parsing assertion"},
   208  		{"aa &&", "Unexpected EOF parsing assertion"},
   209  		{"(aa", "Unbalanced parentheses"},
   210  		{"aa && dns:", "Bad assertion, no value given (key=dns)"},
   211  		{"&& aa", "Unexpected token: &&"},
   212  		{"|| aa", "Unexpected token: ||"},
   213  		{"aa)", "Found junk at end of input: )"},
   214  		{"()", "Illegal parenthetical expression"},
   215  		{"a@pgp", "bad hex string: 'a'"},
   216  		{"aBCP@pgp", "bad hex string: 'abcp'"},
   217  		{"jj@pgp", "bad hex string: 'jj'"},
   218  		{"aa && |bb", "Syntax error when parsing: |bb"},
   219  	}
   220  
   221  	for _, bad := range bads {
   222  		expr, err := AssertionParse(testAssertionContext{}, bad.k)
   223  		if err == nil {
   224  			t.Errorf("Expected a parse error in %s (got %v)", bad, expr)
   225  		} else if err.Error() != bad.v {
   226  			t.Errorf("Got wrong error; wanted '%s', but got '%s'", bad.v, err)
   227  		}
   228  	}
   229  }
   230  
   231  func TestParseAssertionsWithReaders(t *testing.T) {
   232  	units := []struct {
   233  		input   string
   234  		writers string // expected writers (reserialized and comma-sep)
   235  		readers string // expected readers
   236  		error   string // expected error regex
   237  	}{
   238  		{
   239  			input:   "alice,bob&&bob@twitter",
   240  			writers: "alice,bob+bob@twitter",
   241  		},
   242  		{
   243  			input:   "alice,bob&&bob@twitter#char",
   244  			writers: "alice,bob+bob@twitter",
   245  			readers: "char",
   246  		},
   247  		{
   248  			input:   "alice#char,liz",
   249  			writers: "alice",
   250  			readers: "char,liz",
   251  		},
   252  		{
   253  			input:   "alice",
   254  			writers: "alice",
   255  		},
   256  		{
   257  			// doesn't dedup at the moment
   258  			input:   "alice#alice",
   259  			writers: "alice",
   260  			readers: "alice",
   261  		},
   262  		{
   263  			input:   "alice+github:alice",
   264  			writers: "alice+alice@github",
   265  		},
   266  		{
   267  			input:   "1f5DE74F4D4E8884775F2BF1514FC07220D4A61A@pgp,milessteele.com@https",
   268  			writers: "1f5de74f4d4e8884775f2bf1514fc07220d4a61a@pgp,milessteele.com@https",
   269  		},
   270  		{
   271  			input: "",
   272  			error: `^empty assertion$`,
   273  		},
   274  		{
   275  			input: "#char,liz",
   276  			error: `.*`,
   277  		},
   278  		{
   279  			input: "char||liz",
   280  			error: `disallowed.*OR`,
   281  		},
   282  	}
   283  
   284  	ser := func(exprs []AssertionExpression) string {
   285  		var strs []string
   286  		for _, expr := range exprs {
   287  			strs = append(strs, expr.String())
   288  		}
   289  		return strings.Join(strs, ",")
   290  	}
   291  
   292  	for i, unit := range units {
   293  		t.Logf("%v: %v", i, unit.input)
   294  		writers, readers, err := ParseAssertionsWithReaders(testAssertionContext{}, unit.input)
   295  		if len(unit.error) == 0 {
   296  			require.NoError(t, err)
   297  			require.Equal(t, unit.writers, ser(writers))
   298  			require.Equal(t, unit.readers, ser(readers))
   299  		} else {
   300  			require.Error(t, err)
   301  			require.Regexp(t, unit.error, err.Error())
   302  		}
   303  	}
   304  }