mirror of
https://github.com/CompeyDev/lei.git
synced 2024-12-12 04:40:42 +00:00
init: initial work on luau bindings
This commit is contained in:
commit
e17ec038cd
14 changed files with 482 additions and 0 deletions
22
.editorconfig
Normal file
22
.editorconfig
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[{*.go,Makefile,.gitmodules,go.mod,go.sum}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_style = tab
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml,json}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{js,jsx,ts,tsx,css,less,sass,scss,vue,py}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* -text
|
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Mac OS X files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||||
|
.glide/
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "internal/luau"]
|
||||||
|
path = internal/luau
|
||||||
|
url = https://github.com/luau-lang/luau
|
13
.vscode/settings.json
vendored
Normal file
13
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"lobject.h": "c",
|
||||||
|
"lualib.h": "c",
|
||||||
|
"lua.h": "c",
|
||||||
|
"luaconf.h": "c",
|
||||||
|
"cstdint": "c",
|
||||||
|
"stdlib.h": "c"
|
||||||
|
},
|
||||||
|
"go.toolsEnvVars": {
|
||||||
|
"CGO_LDFLAGS_ALLOW":".*"
|
||||||
|
}
|
||||||
|
}
|
9
examples/.gitkeep
Normal file
9
examples/.gitkeep
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# `/examples`
|
||||||
|
|
||||||
|
Examples for your applications and/or public libraries.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
* https://github.com/nats-io/nats.go/tree/master/examples
|
||||||
|
* https://github.com/docker-slim/docker-slim/tree/master/examples
|
||||||
|
* https://github.com/hashicorp/packer/tree/master/examples
|
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/CompeyDev/gluau
|
||||||
|
|
||||||
|
go 1.19
|
18
internal/clua.c
Normal file
18
internal/clua.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <lua.h>
|
||||||
|
#include <_cgo_export.h>
|
||||||
|
|
||||||
|
void* clua_alloc(void* ud, void *ptr, size_t osize, size_t nsize)
|
||||||
|
{
|
||||||
|
return (void*) go_allocf((GoUintptr) ud,(GoUintptr) ptr, osize, nsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* clua_newstate(void* goallocf)
|
||||||
|
{
|
||||||
|
return lua_newstate(&clua_alloc, goallocf);
|
||||||
|
}
|
||||||
|
|
||||||
|
l_noret cluaL_errorL(lua_State* L, char* msg)
|
||||||
|
{
|
||||||
|
return luaL_error(L, msg);
|
||||||
|
}
|
6
internal/clua.h
Normal file
6
internal/clua.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <lua.h>
|
||||||
|
|
||||||
|
void* clua_alloc(void* ud, void *ptr, size_t osize, size_t nsize);
|
||||||
|
lua_State* clua_newstate(void* goallocf);
|
||||||
|
l_noret cluaL_errorL(lua_State* L, char* msg);
|
187
internal/lauxlib.go
Normal file
187
internal/lauxlib.go
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -I${SRCDIR}
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <clua.h>
|
||||||
|
|
||||||
|
// From https://golang-nuts.narkive.com/UsNENgyt/cgo-how-to-pass-string-to-char-array
|
||||||
|
static char** makeCharArray(int size) {
|
||||||
|
return calloc(sizeof(char*), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setArrayString(char** a, char* s, int n) {
|
||||||
|
a[n] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeCharArray(char** a, int size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
free(a[i]);
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
type luaL_Reg C.luaL_Reg
|
||||||
|
|
||||||
|
func LRegister(L *C.lua_State, libname string, l *luaL_Reg) {
|
||||||
|
clibname := C.CString(libname)
|
||||||
|
defer C.free(unsafe.Pointer(clibname))
|
||||||
|
|
||||||
|
C.luaL_register(L, clibname, (*C.luaL_Reg)(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LGetMetaField(L *C.lua_State, obj int32, e string) int32 {
|
||||||
|
ce := C.CString(e)
|
||||||
|
defer C.free(unsafe.Pointer(ce))
|
||||||
|
|
||||||
|
return int32(C.luaL_getmetafield(L, C.int(obj), ce))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCallMeta(L *C.lua_State, obj int32, e string) int32 {
|
||||||
|
ce := C.CString(e)
|
||||||
|
defer C.free(unsafe.Pointer(ce))
|
||||||
|
|
||||||
|
return int32(C.luaL_callmeta(L, C.int(obj), ce))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LTypeError(L *C.lua_State, narg int32, tname string) {
|
||||||
|
ctname := C.CString(tname)
|
||||||
|
defer C.free(unsafe.Pointer(ctname))
|
||||||
|
|
||||||
|
C.luaL_typeerrorL(L, C.int(narg), ctname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LArgError(L *C.lua_State, narg int32, extramsg string) {
|
||||||
|
cextramsg := C.CString(extramsg)
|
||||||
|
defer C.free(unsafe.Pointer(cextramsg))
|
||||||
|
|
||||||
|
C.luaL_argerrorL(L, C.int(narg), cextramsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckLString(L *C.lua_State, narg int32, l *uint64) string {
|
||||||
|
p := C.luaL_checklstring(L, C.int(narg), (*C.size_t)(l))
|
||||||
|
defer C.free(unsafe.Pointer(p))
|
||||||
|
|
||||||
|
return C.GoString(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptLString(L *C.lua_State, narg int32, def string, l *uint64) string {
|
||||||
|
cdef := C.CString(def)
|
||||||
|
defer C.free(unsafe.Pointer(cdef))
|
||||||
|
|
||||||
|
p := C.luaL_optlstring(L, C.int(narg), cdef, (*C.ulong)(l))
|
||||||
|
defer C.free(unsafe.Pointer(p))
|
||||||
|
|
||||||
|
return C.GoString(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckNumber(L *C.lua_State, narg int32) lua_Number {
|
||||||
|
return lua_Number(C.luaL_checknumber(L, C.int(narg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptNumber(L *C.lua_State, narg int32, def lua_Number) lua_Number {
|
||||||
|
return lua_Number(C.luaL_optnumber(L, C.int(narg), C.lua_Number(def)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckBoolean(L *C.lua_State, narg int32) bool {
|
||||||
|
return C.luaL_checkboolean(L, C.int(narg)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptBoolean(L *C.lua_State, narg int32, def bool) bool {
|
||||||
|
cdef := C.int(0)
|
||||||
|
if def {
|
||||||
|
cdef = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.luaL_optboolean(L, C.int(narg), cdef) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckInteger(L *C.lua_State, narg int32) lua_Integer {
|
||||||
|
return lua_Integer(C.luaL_checkinteger(L, C.int(narg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptInteger(L *C.lua_State, narg int32, def lua_Integer) lua_Integer {
|
||||||
|
return lua_Integer(C.luaL_optinteger(L, C.int(narg), C.lua_Integer(def)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckUnsigned(L *C.lua_State, narg int32) lua_Unsigned {
|
||||||
|
return lua_Unsigned(C.luaL_checkunsigned(L, C.int(narg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptUnsigned(L *C.lua_State, narg int32, def lua_Unsigned) lua_Unsigned {
|
||||||
|
return lua_Unsigned(C.luaL_optunsigned(L, C.int(narg), C.lua_Unsigned(def)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckVector(L *C.lua_State, narg int32) *float32 {
|
||||||
|
return (*float32)(C.luaL_checkvector(L, C.int(narg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LOptVector(L *C.lua_State, narg int32, def *float32) *float32 {
|
||||||
|
return (*float32)(C.luaL_optvector(L, C.int(narg), (*C.float)(def)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckStack(L *C.lua_State, sz int32, msg string) {
|
||||||
|
cmsg := C.CString(msg)
|
||||||
|
defer C.free(unsafe.Pointer(cmsg))
|
||||||
|
|
||||||
|
C.luaL_checkstack(L, C.int(sz), cmsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckType(L *C.lua_State, narg int32, t int32) {
|
||||||
|
C.luaL_checktype(L, C.int(narg), C.int(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckAny(L *C.lua_State, narg int32) {
|
||||||
|
C.luaL_checkany(L, C.int(narg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LNewMetatable(L *C.lua_State, tname string) bool {
|
||||||
|
ctname := C.CString(tname)
|
||||||
|
defer C.free(unsafe.Pointer(ctname))
|
||||||
|
|
||||||
|
return C.luaL_newmetatable(L, ctname) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckUdata(L *C.lua_State, ud int32, tname string) unsafe.Pointer {
|
||||||
|
ctname := C.CString(tname)
|
||||||
|
defer C.free(unsafe.Pointer(ctname))
|
||||||
|
|
||||||
|
return C.luaL_checkudata(L, C.int(ud), ctname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckBuffer(L *C.lua_State, narg int32, len *uint64) unsafe.Pointer {
|
||||||
|
return C.luaL_checkbuffer(L, C.int(narg), (*C.size_t)(len))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LWhere(L *C.lua_State, lvl int32) {
|
||||||
|
C.luaL_where(L, C.int(lvl))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: It's not possible to pass varargs from Go->C via cgo, so instead we
|
||||||
|
// expect the user to format the message and hand it over to us, which we
|
||||||
|
// pass to luaL_errorL. This is an inconsistency with the actual C API, but
|
||||||
|
// there isn't really anything we can do.
|
||||||
|
func LErrorL(L *C.lua_State, msg string) {
|
||||||
|
cmsg := C.CString(msg)
|
||||||
|
defer C.free(unsafe.Pointer(cmsg))
|
||||||
|
|
||||||
|
C.cluaL_errorL(L, cmsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LCheckOption(L *C.lua_State, narg int32, def string, lst []string) int32 {
|
||||||
|
cdef := C.CString(def)
|
||||||
|
defer C.free(unsafe.Pointer(cdef))
|
||||||
|
|
||||||
|
clst := C.makeCharArray(C.int(len(lst)))
|
||||||
|
defer C.freeCharArray(clst, C.int(len(lst)))
|
||||||
|
for i, s := range lst {
|
||||||
|
C.setArrayString(clst, C.CString(s), C.int(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return int32(C.luaL_checkoption(L, C.int(narg), cdef, clst))
|
||||||
|
}
|
186
internal/lua.go
Normal file
186
internal/lua.go
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -Iluau/VM/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include -I${SRCDIR}
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <clua.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
type lua_Number C.double
|
||||||
|
type lua_Integer C.int
|
||||||
|
type lua_Unsigned C.uint
|
||||||
|
|
||||||
|
type lua_CFunction func(L *C.lua_State) C.int
|
||||||
|
type lua_Continuation func(L *C.lua_State, status C.int) C.int
|
||||||
|
|
||||||
|
type lua_Udestructor = func(*C.void)
|
||||||
|
type lua_Destructor = func(L *C.lua_State, _ *C.void)
|
||||||
|
|
||||||
|
type lua_Alloc = func(ud, ptr *C.void, osize, nsize C.size_t) *C.void
|
||||||
|
type clua_Alloc = func(ptr unsafe.Pointer, osize, nsize uint) unsafe.Pointer
|
||||||
|
|
||||||
|
//export go_allocf
|
||||||
|
func go_allocf(fp uintptr, ptr uintptr, osize uint, nsize uint) uintptr {
|
||||||
|
p := ((*((*clua_Alloc)(unsafe.Pointer(fp))))(unsafe.Pointer(ptr), osize, nsize))
|
||||||
|
return uintptr(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ==================
|
||||||
|
// VM state
|
||||||
|
// ==================
|
||||||
|
//
|
||||||
|
|
||||||
|
func NewState(ud unsafe.Pointer) *C.lua_State {
|
||||||
|
return C.clua_newstate(unsafe.Pointer(ud))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LuaClose(L *C.lua_State) {
|
||||||
|
C.lua_close(L)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewThread(L *C.lua_State) *C.lua_State {
|
||||||
|
return C.lua_newthread(L)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MainThread(L *C.lua_State) *C.lua_State {
|
||||||
|
return C.lua_mainthread(L)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetThread(L *C.lua_State) {
|
||||||
|
C.lua_resetthread(L)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsThreadReset(L *C.lua_State) bool {
|
||||||
|
return C.lua_isthreadreset(L) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ==================
|
||||||
|
// VM Stack
|
||||||
|
// ==================
|
||||||
|
//
|
||||||
|
|
||||||
|
func AbsIndex(L *C.lua_State, idx C.int) C.int {
|
||||||
|
return C.lua_absindex(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTop(L *C.lua_State) C.int {
|
||||||
|
return C.lua_gettop(L)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTop(L *C.lua_State, idx C.int) {
|
||||||
|
C.lua_settop(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushValue(L *C.lua_State, idx C.int) {
|
||||||
|
C.lua_pushvalue(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Remove(L *C.lua_State, idx C.int) {
|
||||||
|
C.lua_remove(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Insert(L *C.lua_State, idx C.int) {
|
||||||
|
C.lua_insert(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Replace(L *C.lua_State, idx C.int) {
|
||||||
|
C.lua_replace(L, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckStack(L *C.lua_State, sz C.int) bool {
|
||||||
|
return C.lua_checkstack(L, sz) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func RawCheckStack(L *C.lua_State, sz C.int) {
|
||||||
|
C.lua_rawcheckstack(L, sz)
|
||||||
|
}
|
||||||
|
|
||||||
|
func XMove(from, to *C.lua_State, n C.int) {
|
||||||
|
C.lua_xmove(from, to, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func XPush(from, to *C.lua_State, idx C.int) {
|
||||||
|
C.lua_xpush(from, to, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ======================
|
||||||
|
// Stack Values
|
||||||
|
// ======================
|
||||||
|
//
|
||||||
|
|
||||||
|
func IsNumber(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_isnumber(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsString(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_isstring(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCFunction(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_iscfunction(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsLFunction(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_isLfunction(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsUserData(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_isuserdata(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func Type(L *C.lua_State, idx C.int) bool {
|
||||||
|
return C.lua_type(L, idx) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func TypeName(L *C.lua_State, tp C.int) *C.char {
|
||||||
|
return C.lua_typename(L, tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Equal(L *C.lua_State, idx1, idx2 C.int) bool {
|
||||||
|
return C.lua_equal(L, idx1, idx2) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func RawEqual(L *C.lua_State, idx1, idx2 C.int) bool {
|
||||||
|
return C.lua_rawequal(L, idx1, idx2) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func LessThan(L *C.lua_State, idx1, idx2 C.int) bool {
|
||||||
|
return C.lua_lessthan(L, idx1, idx2) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToNumberX(L *C.lua_State, idx C.int, isnum bool) lua_Number {
|
||||||
|
isnumInner := C.int(0)
|
||||||
|
if isnum {
|
||||||
|
isnumInner = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lua_Number(C.lua_tonumberx(L, idx, &isnumInner))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToIntegerX(L *C.lua_State, idx C.int, isnum bool) lua_Integer {
|
||||||
|
isnumInner := C.int(0)
|
||||||
|
if isnum {
|
||||||
|
isnumInner = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lua_Integer(C.lua_tointegerx(L, idx, &isnumInner))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToUnsignedX(L *C.lua_State, idx C.int, isnum bool) lua_Unsigned {
|
||||||
|
isnumInner := C.int(0)
|
||||||
|
if isnum {
|
||||||
|
isnumInner = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lua_Unsigned(C.lua_tounsignedx(L, idx, &isnumInner))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rest of it
|
||||||
|
// TODO: Convert C.* types in args to go types
|
1
internal/luau
Submodule
1
internal/luau
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4f917420d74aae84912acbaeb42e86691ddea309
|
3
main.go
Normal file
3
main.go
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {}
|
9
test/.gitkeep
Normal file
9
test/.gitkeep
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# `/test`
|
||||||
|
|
||||||
|
Additional external test apps and test data. Feel free to structure the `/test` directory anyway you want. For bigger projects it makes sense to have a data subdirectory. For example, you can have `/test/data` or `/test/testdata` if you need Go to ignore what's in that directory. Note that Go will also ignore directories or files that begin with "." or "_", so you have more flexibility in terms of how you name your test data directory.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
* https://github.com/openshift/origin/tree/master/test (test data is in the `/testdata` subdirectory)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue