github.phpd.cn/thought-machine/please@v12.2.0+incompatible/src/parse/asp/interpreter_test.go (about)

     1  // This is essentially an end-to-end test on the whole thing; since it's
     2  // quite tedious to write out the AST by hand we interpret sample BUILD files directly.
     3  
     4  package asp
     5  
     6  import (
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"core"
    14  	"parse/rules"
    15  )
    16  
    17  func parseFileToStatements(filename string) (*scope, []*Statement, error) {
    18  	state := core.NewBuildState(1, nil, 4, core.DefaultConfiguration())
    19  	state.Config.BuildConfig = map[string]string{"parser-engine": "python27"}
    20  	pkg := core.NewPackage("test/package")
    21  	parser := NewParser(state)
    22  	parser.MustLoadBuiltins("builtins.build_defs", nil, rules.MustAsset("builtins.build_defs.gob"))
    23  	statements, err := parser.parse(filename)
    24  	if err != nil {
    25  		panic(err)
    26  	}
    27  	statements = parser.optimise(statements)
    28  	parser.interpreter.optimiseExpressions(reflect.ValueOf(statements))
    29  	s, err := parser.interpreter.interpretAll(pkg, statements)
    30  	return s, statements, err
    31  }
    32  
    33  func parseFile(filename string) (*scope, error) {
    34  	s, _, err := parseFileToStatements(filename)
    35  	return s, err
    36  }
    37  
    38  func TestBasic(t *testing.T) {
    39  	s, err := parseFile("src/parse/asp/test_data/basic.build")
    40  	require.NoError(t, err)
    41  	assert.NotNil(t, s.Lookup("test"))
    42  	assert.Panics(t, func() { s.Lookup("wibble") })
    43  	assert.NotNil(t, s.Lookup("True"))
    44  	assert.NotNil(t, s.Lookup("False"))
    45  	assert.NotNil(t, s.Lookup("None"))
    46  }
    47  
    48  func TestFunctionDef(t *testing.T) {
    49  	s, err := parseFile("src/parse/asp/test_data/function_def.build")
    50  	require.NoError(t, err)
    51  	require.NotNil(t, s.Lookup("cc_library"))
    52  	f := s.Lookup("cc_library").(*pyFunc)
    53  	assert.Equal(t, 14, len(f.args))
    54  	assert.Equal(t, 14, len(f.constants))
    55  	assert.Equal(t, 0, len(f.defaults))
    56  	assert.Equal(t, "name", f.args[0])
    57  	assert.Nil(t, f.constants[0])
    58  	assert.Equal(t, "srcs", f.args[1])
    59  	assert.NotNil(t, f.constants[1])
    60  }
    61  
    62  func TestOperators(t *testing.T) {
    63  	s, err := parseFile("src/parse/asp/test_data/interpreter/operators.build")
    64  	require.NoError(t, err)
    65  	require.NotNil(t, s.Lookup("y"))
    66  	i := s.Lookup("y").(pyInt)
    67  	assert.EqualValues(t, 7, i)
    68  	assert.True(t, s.Lookup("z").IsTruthy())
    69  }
    70  
    71  func TestInterpolation(t *testing.T) {
    72  	s, err := parseFile("src/parse/asp/test_data/interpreter/interpolation.build")
    73  	require.NoError(t, err)
    74  	assert.EqualValues(t, "//abc:123", s.Lookup("x"))
    75  }
    76  
    77  func TestCollections(t *testing.T) {
    78  	s, err := parseFile("src/parse/asp/test_data/interpreter/collections.build")
    79  	require.NoError(t, err)
    80  	assert.EqualValues(t, True, s.Lookup("x"))
    81  	assert.EqualValues(t, True, s.Lookup("y"))
    82  	assert.EqualValues(t, False, s.Lookup("z"))
    83  }
    84  
    85  func TestArguments(t *testing.T) {
    86  	s, err := parseFile("src/parse/asp/test_data/interpreter/arguments.build")
    87  	require.NoError(t, err)
    88  	assert.EqualValues(t, "a:b:True", s.Lookup("x"))
    89  	assert.EqualValues(t, "a:b:c", s.Lookup("y"))
    90  	assert.EqualValues(t, "a:b:c", s.Lookup("z"))
    91  }
    92  
    93  func TestMutableArguments(t *testing.T) {
    94  	s, err := parseFile("src/parse/asp/test_data/interpreter/mutable_arguments.build")
    95  	require.NoError(t, err)
    96  	assert.EqualValues(t, 8, s.Lookup("y"))
    97  }
    98  
    99  func TestBuiltins(t *testing.T) {
   100  	s, err := parseFile("src/parse/asp/test_data/interpreter/builtins.build")
   101  	require.NoError(t, err)
   102  	assert.Equal(t, 1, s.pkg.NumTargets())
   103  	assert.NotNil(t, s.pkg.Target("lib"))
   104  }
   105  
   106  func TestParentheses(t *testing.T) {
   107  	s, err := parseFile("src/parse/asp/test_data/interpreter/parentheses.build")
   108  	require.NoError(t, err)
   109  	assert.EqualValues(t, 1, s.Lookup("x"))
   110  }
   111  
   112  func TestComprehensions(t *testing.T) {
   113  	s, err := parseFile("src/parse/asp/test_data/interpreter/comprehensions.build")
   114  	require.NoError(t, err)
   115  	assert.EqualValues(t, pyList{pyString("file1"), pyString("file2")}, s.Lookup("file_srcs"))
   116  	assert.EqualValues(t, pyList{pyString("file1+file1"), pyString("file1+file2"), pyString("file1+:rule1"),
   117  		pyString("file2+file1"), pyString("file2+file2"), pyString("file2+:rule1")}, s.Lookup("pairs"))
   118  }
   119  
   120  func TestEquality(t *testing.T) {
   121  	s, err := parseFile("src/parse/asp/test_data/interpreter/equality.build")
   122  	require.NoError(t, err)
   123  	assert.Equal(t, True, s.Lookup("a"))
   124  	assert.Equal(t, True, s.Lookup("b"))
   125  	assert.Equal(t, False, s.Lookup("c"))
   126  	assert.Equal(t, False, s.Lookup("d"))
   127  	assert.Equal(t, True, s.Lookup("e"))
   128  	assert.Equal(t, False, s.Lookup("f"))
   129  	assert.Equal(t, False, s.Lookup("g"))
   130  }
   131  
   132  func TestSlicing(t *testing.T) {
   133  	s, err := parseFile("src/parse/asp/test_data/interpreter/slicing.build")
   134  	require.NoError(t, err)
   135  	assert.Equal(t, pyInt(2), s.Lookup("a"))
   136  	assert.Equal(t, pyList{pyInt(2), pyInt(3)}, s.Lookup("b"))
   137  	assert.Equal(t, pyList{pyInt(1)}, s.Lookup("c"))
   138  	assert.Equal(t, pyList{pyInt(2)}, s.Lookup("d"))
   139  	assert.Equal(t, pyInt(3), s.Lookup("e"))
   140  	assert.Equal(t, pyList{pyInt(1), pyInt(2)}, s.Lookup("f"))
   141  	assert.Equal(t, pyList{pyInt(1), pyInt(2), pyInt(3)}, s.Lookup("g"))
   142  }
   143  
   144  func TestSorting(t *testing.T) {
   145  	s, err := parseFile("src/parse/asp/test_data/interpreter/sorted.build")
   146  	require.NoError(t, err)
   147  	assert.Equal(t, pyList{pyInt(1), pyInt(2), pyInt(3)}, s.Lookup("y"))
   148  	// N.B. sorted() sorts in-place, unlike Python's one. We may change that later.
   149  }
   150  
   151  func TestUnpacking(t *testing.T) {
   152  	s, err := parseFile("src/parse/asp/test_data/interpreter/unpacking.build")
   153  	require.NoError(t, err)
   154  	assert.EqualValues(t, "a", s.Lookup("a"))
   155  	assert.EqualValues(t, "b", s.Lookup("b"))
   156  	assert.EqualValues(t, "c", s.Lookup("c"))
   157  	assert.EqualValues(t, "abc", s.Lookup("d"))
   158  	assert.EqualValues(t, ".", s.Lookup("e"))
   159  	assert.EqualValues(t, "def", s.Lookup("f"))
   160  }
   161  
   162  func TestPrecedence(t *testing.T) {
   163  	s, err := parseFile("src/parse/asp/test_data/interpreter/precedence.build")
   164  	require.NoError(t, err)
   165  	assert.EqualValues(t, pyList{pyString("a.go")}, s.Lookup("file_srcs"))
   166  }
   167  
   168  func TestPrecedence2(t *testing.T) {
   169  	s, err := parseFile("src/parse/asp/test_data/interpreter/precedence2.build")
   170  	require.NoError(t, err)
   171  	assert.True(t, s.Lookup("y").IsTruthy())
   172  }
   173  
   174  func TestZip(t *testing.T) {
   175  	s, err := parseFile("src/parse/asp/test_data/interpreter/zip.build")
   176  	require.NoError(t, err)
   177  	expected := pyList{
   178  		pyList{pyInt(1), pyInt(4), pyInt(7)},
   179  		pyList{pyInt(2), pyInt(5), pyInt(8)},
   180  		pyList{pyInt(3), pyInt(6), pyInt(9)},
   181  	}
   182  	assert.EqualValues(t, expected, s.Lookup("x"))
   183  }
   184  
   185  func TestOptimisations(t *testing.T) {
   186  	s, err := parseFile("src/parse/asp/test_data/interpreter/optimisations.build")
   187  	require.NoError(t, err)
   188  	assert.EqualValues(t, "python2.7", s.Lookup("PARSER_LIB_NAME"))
   189  }
   190  
   191  func TestContinue(t *testing.T) {
   192  	s, err := parseFile("src/parse/asp/test_data/interpreter/continue.build")
   193  	require.NoError(t, err)
   194  	assert.EqualValues(t, pyList{pyInt(4), pyInt(5)}, s.Lookup("a"))
   195  }
   196  
   197  func TestAliases(t *testing.T) {
   198  	s, err := parseFile("src/parse/asp/test_data/interpreter/aliases.build")
   199  	require.NoError(t, err)
   200  	assert.EqualValues(t, 42, s.Lookup("v"))
   201  }
   202  
   203  func TestPaths(t *testing.T) {
   204  	s, err := parseFile("src/parse/asp/test_data/interpreter/paths.build")
   205  	require.NoError(t, err)
   206  	assert.EqualValues(t, "a/b/c", s.Lookup("a"))
   207  	assert.EqualValues(t, "a/c", s.Lookup("b"))
   208  	assert.EqualValues(t, pyList{pyString("a/b"), pyString("c")}, s.Lookup("c"))
   209  	assert.EqualValues(t, pyList{pyString(""), pyString("a")}, s.Lookup("d"))
   210  	assert.EqualValues(t, pyList{pyString("a/test"), pyString(".txt")}, s.Lookup("e"))
   211  	assert.EqualValues(t, pyList{pyString("a/test"), pyString("")}, s.Lookup("f"))
   212  	assert.EqualValues(t, "c", s.Lookup("g"))
   213  	assert.EqualValues(t, "a", s.Lookup("h"))
   214  	assert.EqualValues(t, "a/b", s.Lookup("i"))
   215  	assert.EqualValues(t, "", s.Lookup("j"))
   216  }
   217  
   218  func TestStrings(t *testing.T) {
   219  	s, err := parseFile("src/parse/asp/test_data/interpreter/strings.build")
   220  	require.NoError(t, err)
   221  	assert.EqualValues(t, pyList{
   222  		pyString("acpi"), pyString("base64"), pyString("basename"), pyString("blkid"), pyString("blockdev"),
   223  		pyString("bunzip2"), pyString("bzcat"), pyString("cal"), pyString("cat"), pyString("catv"),
   224  		pyString("chattr"), pyString("whoami"), pyString("xargs"), pyString("xxd"), pyString("yes"),
   225  	}, s.Lookup("TOYS2"))
   226  	assert.EqualValues(t, "acpi base64 basename blkid blockdev bunzip2 bzcat cal cat catv chattr\nwhoami xargs xxd yes", s.Lookup("TOYS3"))
   227  }
   228  
   229  func TestArgumentCompatibility(t *testing.T) {
   230  	// This isn't a totally obvious property of the interpreter, but when an argument specifies
   231  	// a type and is given None, we adopt the default. This allows external functions to use None
   232  	// for various arguments (e.g. deps), but internally we can treat them as lists.
   233  	s, err := parseFile("src/parse/asp/test_data/interpreter/argument_compatibility.build")
   234  	require.NoError(t, err)
   235  	assert.EqualValues(t, pyList{pyInt(1)}, s.Lookup("x"))
   236  }
   237  
   238  func TestOptimiseConfig(t *testing.T) {
   239  	s, statements, err := parseFileToStatements("src/parse/asp/test_data/interpreter/optimise_config.build")
   240  	assert.NoError(t, err)
   241  	assert.Equal(t, 1, len(statements))
   242  	assert.NotNil(t, statements[0].Ident)
   243  	assert.NotNil(t, statements[0].Ident.Action)
   244  	assert.NotNil(t, statements[0].Ident.Action.Assign)
   245  	assert.Equal(t, "GO_TOOL", statements[0].Ident.Action.Assign.Optimised.Config)
   246  	assert.EqualValues(t, "go", s.Lookup("x"))
   247  }