go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/quota/internal/luatest/lua_test.go (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package luatest
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"path/filepath"
    21  	"regexp"
    22  	"strconv"
    23  	"strings"
    24  	"testing"
    25  
    26  	luajson "github.com/alicebob/gopher-json"
    27  	lua "github.com/yuin/gopher-lua"
    28  
    29  	. "github.com/smartystreets/goconvey/convey"
    30  )
    31  
    32  func intMin(a, b int) int {
    33  	if a < b {
    34  		return a
    35  	}
    36  	return b
    37  }
    38  
    39  var hexFinder = regexp.MustCompile(`\\x[a-f0-9]{2}`)
    40  
    41  // hackedFormat is like the built in implementation of string.format, except
    42  // that it correctly implements %q on strings containing binary characters.
    43  func hackedFormat(L *lua.LState) int {
    44  	str := L.CheckString(1)
    45  	args := make([]any, L.GetTop()-1)
    46  	top := L.GetTop()
    47  	for i := 2; i <= top; i++ {
    48  		args[i-2] = L.Get(i)
    49  	}
    50  	npat := strings.Count(str, "%") - strings.Count(str, "%%")
    51  
    52  	ret := hexFinder.ReplaceAllStringFunc(fmt.Sprintf(str, args[:intMin(npat, len(args))]...), func(s string) string {
    53  		dec, err := strconv.ParseUint(s[2:], 16, 8)
    54  		if err != nil {
    55  			panic(err)
    56  		}
    57  		return fmt.Sprintf("\\%03d", dec)
    58  	})
    59  
    60  	L.Push(lua.LString(ret))
    61  	return 1
    62  }
    63  
    64  func check(err error) {
    65  	if err != nil {
    66  		panic(err)
    67  	}
    68  }
    69  
    70  func TestLua(t *testing.T) {
    71  	// gopher-lua doesn't implement os.date correctly, so having this unset
    72  	// results in a crash because luaunt passes the result of os.getenv as the
    73  	// first argument to `os.date` which doesn't like `args.n == 1` with the arg
    74  	// value being nil. So, we set it to the real default explicitly.
    75  	check(os.Setenv("LUAUNIT_DATEFMT", "%c"))
    76  	defer func() {
    77  		check(os.Unsetenv("LUAUNIT_DATEFMT"))
    78  	}()
    79  	oldLuaPath := os.Getenv("LUA_PATH")
    80  	if os.Unsetenv("LUA_PATH") == nil {
    81  		defer func() {
    82  			check(os.Setenv("LUA_PATH", oldLuaPath))
    83  		}()
    84  	}
    85  	check(os.Chdir("testdata"))
    86  	defer func() {
    87  		check(os.Chdir(".."))
    88  	}()
    89  
    90  	matches, err := filepath.Glob("*_test.lua")
    91  	if err != nil {
    92  		t.Fatalf("could not glob: %s", err)
    93  	}
    94  	if len(matches) == 0 {
    95  		t.Fatal("found no lua tests")
    96  	}
    97  
    98  	Convey(`lua`, t, func() {
    99  		for _, filename := range matches {
   100  			Convey(filename, func(c C) {
   101  				L := lua.NewState(lua.Options{})
   102  				defer L.Close()
   103  
   104  				// install `cjson` global; used for DUMP debugging function.
   105  				luajson.Loader(L)
   106  				mod := L.Get(1)
   107  				L.Pop(1)
   108  				L.SetGlobal("cjson", mod)
   109  
   110  				L.GetGlobal("string").(*lua.LTable).RawSet(lua.LString("format"), L.NewFunction(hackedFormat))
   111  				So(L.DoFile(filename), ShouldBeNil)
   112  				SoMsg("luaunit tests failed", L.CheckInt(1), ShouldEqual, 0)
   113  				_, err := Println() // space between luaunit outputs
   114  				So(err, ShouldBeNil)
   115  			})
   116  		}
   117  	})
   118  }