Skip to content

The library that implements the compiling and running of a code written in the Go programming language and running of a test case set for the compiled code (i.e. the executable file)

License

Notifications You must be signed in to change notification settings

thewizardplusplus/go-code-runner

Repository files navigation

go-code-runner

GoDoc Go Report Card Build Status codecov

The library that implements the compiling and running of a code written in the Go programming language and running of a test case set for the compiled code (i.e. the executable file).

Features

  • saving of a code to a temporary file:
    • storing of the temporary file with the code to an individual temporary directory;
  • checking of package imports used in the code written in the Go programming language:
    • checking based on the set of allowed imports;
  • compiling of a code written in the Go programming language:
    • automatic importing of the packages used in the code (optionally);
    • checking of package imports used in the code (optionally):
      • checking based on the set of allowed imports;
    • enriching of an error of the external command running by an output from the stderr stream;
    • support for the running time management (via the Go context);
  • running of the compiled code (i.e. the executable file):
    • passing of a custom input as the stdin stream;
    • returning of an output from the stdout stream;
    • enriching of an error of the external command running by an output from the stderr stream;
    • support for the running time management (via the Go context);
  • running of a test case set for the compiled code (i.e. the executable file):
    • representation of a test case:
      • input;
      • expected output;
    • checking of an actual output in each test case:
      • returning of the sentinel errors:
        • failed running — it returns on a running error;
        • unexpected output — it returns when the expected and actual outputs do not match;
    • support for the running time management (via the Go context).

Installation

Prepare the directory:

$ mkdir --parents "$(go env GOPATH)/src/github.com/thewizardplusplus/"
$ cd "$(go env GOPATH)/src/github.com/thewizardplusplus/"

Clone this repository:

$ git clone https://github.com/thewizardplusplus/go-code-runner.git
$ cd go-code-runner

Install dependencies with the dep tool:

$ dep ensure -vendor-only

Example

coderunner.CheckImports() (success):

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	mapset "github.com/deckarep/golang-set"
	coderunner "github.com/thewizardplusplus/go-code-runner"
	systemutils "github.com/thewizardplusplus/go-code-runner/system-utils"
)

func main() {
	const code = `
		package main

		import (
			"fmt"
			"log"
		)

		func main() {
			var x, y int
			if _, err := fmt.Scan(&x, &y); err != nil {
				log.Fatal(err)
			}

			fmt.Println(x + y)
		}
	`

	pathToCode, err := systemutils.SaveTemporaryText(code, ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(filepath.Dir(pathToCode)) // nolint: errcheck

	err = coderunner.CheckImports(pathToCode, mapset.NewSet("fmt", "log"))
	fmt.Printf("%v\n", err)

	// Output:
	// <nil>
}

coderunner.CheckImports() (error):

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	mapset "github.com/deckarep/golang-set"
	coderunner "github.com/thewizardplusplus/go-code-runner"
	systemutils "github.com/thewizardplusplus/go-code-runner/system-utils"
)

func main() {
	const code = `
		package main

		import (
			"fmt"
			"log"
		)

		func main() {
			var x, y int
			if _, err := fmt.Scan(&x, &y); err != nil {
				log.Fatal(err)
			}

			fmt.Println(x + y)
		}
	`

	pathToCode, err := systemutils.SaveTemporaryText(code, ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(filepath.Dir(pathToCode)) // nolint: errcheck

	err = coderunner.CheckImports(pathToCode, mapset.NewSet("log"))
	fmt.Printf("%v\n", err)

	// Output:
	// disallowed import "fmt"
}

coderunner.CompileCode():

package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"path/filepath"

	coderunner "github.com/thewizardplusplus/go-code-runner"
	systemutils "github.com/thewizardplusplus/go-code-runner/system-utils"
)

func main() {
	const code = `
		package main

		func main() {
			var x, y int
			fmt.Scan(&x, &y)

			fmt.Println(x + y)
		}
	`

	pathToCode, err := systemutils.SaveTemporaryText(code, ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(filepath.Dir(pathToCode)) // nolint: errcheck

	pathToExecutable, err :=
		coderunner.CompileCode(context.Background(), pathToCode, nil)
	if err != nil {
		log.Fatal(err)
	}

	output, err :=
		systemutils.RunCommand(context.Background(), "2 3", pathToExecutable)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%q\n", output)

	// Output:
	// "5\n"
}

testrunner.RunTestCases() (success):

package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"path/filepath"

	coderunner "github.com/thewizardplusplus/go-code-runner"
	systemutils "github.com/thewizardplusplus/go-code-runner/system-utils"
	testrunner "github.com/thewizardplusplus/go-code-runner/test-runner"
)

func main() {
	const code = `
		package main

		func main() {
			var x, y int
			fmt.Scan(&x, &y)

			fmt.Println(x + y)
		}
	`

	pathToCode, err := systemutils.SaveTemporaryText(code, ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(filepath.Dir(pathToCode)) // nolint: errcheck

	pathToExecutable, err :=
		coderunner.CompileCode(context.Background(), pathToCode, nil)
	if err != nil {
		log.Fatal(err)
	}

	err = testrunner.RunTestCases(
		context.Background(),
		[]testrunner.TestCase{
			{Input: "5 12", ExpectedOutput: "17\n"},
			{Input: "23 42", ExpectedOutput: "65\n"},
		},
		func(ctx context.Context, input string) (output string, err error) {
			return systemutils.RunCommand(ctx, input, pathToExecutable)
		},
	)
	fmt.Printf("%v\n", err)

	// Output:
	// <nil>
}

testrunner.RunTestCases() (error):

package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"path/filepath"

	coderunner "github.com/thewizardplusplus/go-code-runner"
	systemutils "github.com/thewizardplusplus/go-code-runner/system-utils"
	testrunner "github.com/thewizardplusplus/go-code-runner/test-runner"
)

func main() {
	const code = `
		package main

		func main() {
			var x, y int
			fmt.Scan(&x, &y)

			fmt.Println(x + y)
		}
	`

	pathToCode, err := systemutils.SaveTemporaryText(code, ".go")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(filepath.Dir(pathToCode)) // nolint: errcheck

	pathToExecutable, err :=
		coderunner.CompileCode(context.Background(), pathToCode, nil)
	if err != nil {
		log.Fatal(err)
	}

	err = testrunner.RunTestCases(
		context.Background(),
		[]testrunner.TestCase{
			{Input: "5 12", ExpectedOutput: "17\n"},
			{Input: "23 42", ExpectedOutput: "100\n"},
		},
		func(ctx context.Context, input string) (output string, err error) {
			return systemutils.RunCommand(ctx, input, pathToExecutable)
		},
	)
	fmt.Printf("%v\n", err)

	// Output:
	// unexpected output (input - "23 42"): expected - "100\n", actual - "65\n"
}

License

The MIT License (MIT)

Copyright © 2021 thewizardplusplus

About

The library that implements the compiling and running of a code written in the Go programming language and running of a test case set for the compiled code (i.e. the executable file)

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages