env GOPRIVATE='test/main,private.source'

garble build
exec ./main$exe
cmp stderr main.stderr

! binsubstr main$exe 'localName' 'globalConst' 'globalVar' 'globalType' 'valuable information' 'private.source' 'remoteIntReturn' 'intReturn' 'neverInlined'

[short] stop # no need to verify this with -short

# Check that the program works as expected without garble.
go build
exec ./main$exe
cmp stderr main.stderr

binsubstr main$exe 'globalVar' # 'globalType' only matches on go < 1.15
! binsubstr main$exe 'localName' 'globalConst' 'remoteIntReturn' 'intReturn'

-- extra/go.mod --
module private.source/extra

go 1.15
-- extra/extra.go --
package extra

func Func() string {
	return "This is a separate module to obfuscate."
}
-- go.mod --
module test/main

go 1.15

// We include an extra module to obfuscate, included in the same original source
// code via a replace directive.
require private.source/extra v0.0.0-00010101000000-000000000000

replace private.source/extra => ./extra
-- main.go --
package main

import (
	"encoding/json"
	"go/ast"
	"reflect"

	"private.source/extra"
	"test/main/sub"
)

// This comment contains valuable information. Ensure it's not in the final binary.
var V interface{}

type T struct {
	ast.Node
	*ast.Ident
}

type EncodingT struct {
	Foo int
}

type Embedded int

type Embedding struct {
	Embedded
}

type embedded int

type embedding struct {
	embedded
}

// embedded fields whose type is in the universe scope used to crash garble
type EmbeddingUniverseScope struct {
	error
	int
	string
}

// TODO: test that go:noinline still works without using debugdir

//go:noinline
func neverInlined() {
	println("This func is never inlined.")
}

func main() {
	switch V := V.(type) {
	case int:
		var _ int = V
	case nil:
		println("nil case")
	}

	var _ = reflect.TypeOf(EncodingT{})
	enc, _ := json.Marshal(EncodingT{Foo: 3})
	println(string(enc))
	scopesTest()
	println(extra.Func())
	sub.Test()
	neverInlined()
}

-- scopes.go --
package main

const globalConst = 1

type globalType int

var (
	globalVar                 = 1
	globalVarTyped globalType = 1
)

func scopesTest() {
	println(globalVar, globalConst, globalVarTyped)
	const localNameConst = 1

	localNameShort := 4

	type localNameType int

	var (
		localNameVar                   = 5
		localNameTypeVar localNameType = 1
	)

	println(localNameConst, localNameShort, localNameVar, localNameTypeVar, input("input"))
}

func input(localNameParam string) (localNameReturn string) { return localNameParam }

-- sub/names.go --
package sub

var someGlobalVar0 = "0"
var someGlobalVar1 = "1"
var someGlobalVar2 = "2"

func Test() {
	var A, B, C, D, E string
	noop(A, B, C, D, E)
	if someGlobalVar0 != "0" || someGlobalVar1 != "1" || someGlobalVar2 != "2"{
		panic("name collision detected")
	}
}

func noop(...interface{}) {}

// Funcs that almost look like test funcs used to make garble panic.

func TestFoo(s string) {}

func TestBar(*struct{}) {}

-- main.stderr --
nil case
{"Foo":3}
1 1 1
1 4 5 1 input
This is a separate module to obfuscate.
This func is never inlined.
