github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/pkg/transpiler/transpiler_test.go (about)

     1  package transpiler
     2  
     3  import (
     4  	"go/ast"
     5  	goscanner "go/scanner"
     6  	"go/token"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestTranspile(t *testing.T) {
    15  	t.Parallel()
    16  
    17  	cases := []struct {
    18  		name            string
    19  		tags            string
    20  		source          string
    21  		expectedOutput  string
    22  		expectedImports []*ast.ImportSpec
    23  		expectedError   string
    24  	}{
    25  		{
    26  			name: "hello",
    27  			source: `
    28  package foo
    29  
    30  func hello() string { return "world"}
    31  `,
    32  			expectedOutput: `
    33  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
    34  
    35  //line foo.gno:1:1
    36  package foo
    37  
    38  func hello() string { return "world" }
    39  `,
    40  		},
    41  		{
    42  			name: "hello with tags",
    43  			tags: "gno",
    44  			source: `
    45  package foo
    46  
    47  func hello() string { return "world"}
    48  `,
    49  			expectedOutput: `
    50  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
    51  
    52  //go:build gno
    53  
    54  //line foo.gno:1:1
    55  package foo
    56  
    57  func hello() string { return "world" }
    58  `,
    59  		},
    60  		{
    61  			name: "use-std",
    62  			source: `
    63  package foo
    64  
    65  import "std"
    66  
    67  func hello() string {
    68  	_ = std.Foo
    69  	return "world"
    70  }
    71  `,
    72  			expectedOutput: `
    73  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
    74  
    75  //line foo.gno:1:1
    76  package foo
    77  
    78  import "github.com/gnolang/gno/gnovm/stdlibs/stdshim"
    79  
    80  func hello() string {
    81  	_ = std.Foo
    82  	return "world"
    83  }
    84  `,
    85  			expectedImports: []*ast.ImportSpec{
    86  				{
    87  					Path: &ast.BasicLit{
    88  						ValuePos: 21,
    89  						Kind:     9,
    90  						Value:    `"github.com/gnolang/gno/gnovm/stdlibs/stdshim"`,
    91  					},
    92  					EndPos: 26,
    93  				},
    94  			},
    95  		},
    96  		{
    97  			name: "use-realm",
    98  			source: `
    99  package foo
   100  
   101  import "gno.land/r/users"
   102  
   103  func foo()  { _ = users.Register}
   104  `,
   105  			expectedOutput: `
   106  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
   107  
   108  //line foo.gno:1:1
   109  package foo
   110  
   111  import "github.com/gnolang/gno/examples/gno.land/r/users"
   112  
   113  func foo() { _ = users.Register }
   114  `,
   115  			expectedImports: []*ast.ImportSpec{
   116  				{
   117  					Path: &ast.BasicLit{
   118  						ValuePos: 21,
   119  						Kind:     9,
   120  						Value:    `"github.com/gnolang/gno/examples/gno.land/r/users"`,
   121  					},
   122  					EndPos: 39,
   123  				},
   124  			},
   125  		},
   126  		{
   127  			name: "use-avl",
   128  			source: `
   129  package foo
   130  
   131  import "gno.land/p/demo/avl"
   132  
   133  func foo()  { _ = avl.Tree }
   134  `,
   135  			expectedOutput: `
   136  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
   137  
   138  //line foo.gno:1:1
   139  package foo
   140  
   141  import "github.com/gnolang/gno/examples/gno.land/p/demo/avl"
   142  
   143  func foo() { _ = avl.Tree }
   144  `,
   145  			expectedImports: []*ast.ImportSpec{
   146  				{
   147  					Path: &ast.BasicLit{
   148  						ValuePos: 21,
   149  						Kind:     9,
   150  						Value:    `"github.com/gnolang/gno/examples/gno.land/p/demo/avl"`,
   151  					},
   152  					EndPos: 42,
   153  				},
   154  			},
   155  		},
   156  		{
   157  			name: "use-named-std",
   158  			source: `
   159  package foo
   160  
   161  import bar "std"
   162  
   163  func hello() string {
   164  	_ = bar.Foo
   165  	return "world"
   166  }
   167  `,
   168  			expectedOutput: `
   169  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
   170  
   171  //line foo.gno:1:1
   172  package foo
   173  
   174  import bar "github.com/gnolang/gno/gnovm/stdlibs/stdshim"
   175  
   176  func hello() string {
   177  	_ = bar.Foo
   178  	return "world"
   179  }
   180  `,
   181  			expectedImports: []*ast.ImportSpec{
   182  				{
   183  					Name: &ast.Ident{
   184  						NamePos: 21,
   185  						Name:    "bar",
   186  					},
   187  					Path: &ast.BasicLit{
   188  						ValuePos: 25,
   189  						Kind:     9,
   190  						Value:    `"github.com/gnolang/gno/gnovm/stdlibs/stdshim"`,
   191  					},
   192  					EndPos: 30,
   193  				},
   194  			},
   195  		},
   196  		{
   197  			name: "blacklisted-package",
   198  			source: `
   199  package foo
   200  
   201  import "reflect"
   202  
   203  func foo() { _ = reflect.ValueOf }
   204  `,
   205  			expectedError: `transpileAST: foo.gno:3:8: import "reflect" is not in the whitelist`,
   206  		},
   207  		{
   208  			name: "syntax-error",
   209  			source: `
   210  package foo
   211  
   212  invalid
   213  `,
   214  			expectedError: `parse: foo.gno:3:1: expected declaration, found invalid`,
   215  		},
   216  		{
   217  			name: "unknown-realm",
   218  			source: `
   219  package foo
   220  
   221  import "gno.land/p/demo/unknownxyz"
   222  `,
   223  			expectedOutput: `
   224  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
   225  
   226  //line foo.gno:1:1
   227  package foo
   228  
   229  import "github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz"
   230  `,
   231  			expectedImports: []*ast.ImportSpec{
   232  				{
   233  					Path: &ast.BasicLit{
   234  						ValuePos: 21,
   235  						Kind:     9,
   236  						Value:    `"github.com/gnolang/gno/examples/gno.land/p/demo/unknownxyz"`,
   237  					},
   238  					EndPos: 49,
   239  				},
   240  			},
   241  		},
   242  		{
   243  			name: "whitelisted-package",
   244  			source: `
   245  package foo
   246  
   247  import "regexp"
   248  
   249  func foo() { _ = regexp.MatchString }
   250  `,
   251  			expectedOutput: `
   252  // Code generated by github.com/gnolang/gno. DO NOT EDIT.
   253  
   254  //line foo.gno:1:1
   255  package foo
   256  
   257  import "regexp"
   258  
   259  func foo() { _ = regexp.MatchString }
   260  `,
   261  			expectedImports: []*ast.ImportSpec{
   262  				{
   263  					Path: &ast.BasicLit{
   264  						ValuePos: 21,
   265  						Kind:     9,
   266  						Value:    `"regexp"`,
   267  					},
   268  				},
   269  			},
   270  		},
   271  	}
   272  	for _, c := range cases {
   273  		c := c // scopelint
   274  		t.Run(c.name, func(t *testing.T) {
   275  			t.Parallel()
   276  			// "\n" is added for better test case readability, now trim it
   277  			source := strings.TrimPrefix(c.source, "\n")
   278  
   279  			res, err := Transpile(source, c.tags, "foo.gno")
   280  
   281  			if c.expectedError != "" {
   282  				require.EqualError(t, err, c.expectedError)
   283  				return
   284  			}
   285  			require.NoError(t, err)
   286  			expectedOutput := strings.TrimPrefix(c.expectedOutput, "\n")
   287  			assert.Equal(t, expectedOutput, res.Translated, "wrong output")
   288  			assert.Equal(t, c.expectedImports, res.Imports, "wrong imports")
   289  		})
   290  	}
   291  }
   292  
   293  func TestParseGoBuildErrors(t *testing.T) {
   294  	tests := []struct {
   295  		name          string
   296  		output        string
   297  		expectedError error
   298  	}{
   299  		{
   300  			name:          "empty output",
   301  			output:        "",
   302  			expectedError: nil,
   303  		},
   304  		{
   305  			name:          "random output",
   306  			output:        "xxx",
   307  			expectedError: nil,
   308  		},
   309  		{
   310  			name: "some errors",
   311  			output: `xxx
   312  main.gno:6:2: nasty error
   313  pkg/file.gno:60:20: ugly error`,
   314  			expectedError: goscanner.ErrorList{
   315  				&goscanner.Error{
   316  					Pos: token.Position{
   317  						Filename: "main.gno",
   318  						Line:     6,
   319  						Column:   2,
   320  					},
   321  					Msg: "nasty error",
   322  				},
   323  				&goscanner.Error{
   324  					Pos: token.Position{
   325  						Filename: "pkg/file.gno",
   326  						Line:     60,
   327  						Column:   20,
   328  					},
   329  					Msg: "ugly error",
   330  				},
   331  			},
   332  		},
   333  	}
   334  	for _, tt := range tests {
   335  		t.Run(tt.name, func(t *testing.T) {
   336  			err := parseGoBuildErrors(tt.output)
   337  
   338  			assert.Equal(t, tt.expectedError, err)
   339  		})
   340  	}
   341  }