osa

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2021 License: GPL-3.0 Imports: 3 Imported by: 4

README

OSA – OS abstraction package

Go code (golang) packages that offer easy in-memory testing of code calling os functions without reading/writing real files, or requiring extensive refactoring or dependency injection.

Contents

Features

  • Use os.* functions like you normally would.
  • Monkey-patch in-memory os replacement during testing, allowing for:
    • Fast file I/O tests without causing any real filesystem reads or writes.
    • Simple stdio (stdin/stdou/stderr) testing without needing to call a subprocess.
    • Exit code catching & testing without needing to call a subprocess.
  • Support for most os functions (as of Go 1.17).
  • No extensive rewrites or dependency injections required.
  • Common os assert/require test utility functions included.

Packages

The following packages are included:

  • osa: The main OS abstraction package. It determines which os functions are supported and tracks the currently active implementation. Implementing packages simply need to import this package instead of "os", no further changes required.
  • osa/oos: The standard osa implementation. This package simply wraps and calls the default os functions of the standard library. This is the default osa implementation, so typically code does not need to import or directly interact with this package.
  • osa/vos: The virtual osa implementation. This package mimicks os features in-memory, so no real files are created, read, updated, or deleted. The package provides a Patch() function to inject this implementation for testing. Only test packages need to know about this.
  • osa/testos: An OS testing helpers library. This package provides useful helper functions for repetitive os calls and assert/require operations during testing, such as RequireWrite(), RequireMkdirAll(), AssertNotExists(), AssertFileData(), GetStdio(), and more.
  • osa/testosa: An OSA testing library. This package provides assertions for custom OSA implementations.

Basic Usage (TLDR)

Use osa package instead of os:

import (
-	"os"
+	os "github.com/echocrow/osa"
)

Patch & use in-memory implementation via osa/vos during testing:

import (
	"testing"
+	"github.com/echocrow/osa/vos"
)

func TestExample(t *testing.T) {
+	os, reset := vos.Patch()
+	defer reset()
	// ...
}

Extended Usage

Implementation

In the implementing package, use osa instead of the original os package via an aliased import:

package example

import (
	// Import "osa" instead of the standard "os" package.
	os "github.com/echocrow/osa"
)

// No other code changes required; use "os" as usual, e.g.:
func Example() string {
	if data, err := os.ReadFile("my-file.go"); err != nil {
		return ""
	}
	return data
}

By default, this will simply call the original implementation of the standard os package.

Testing

In the testing package, the virtual OS package (vos) can be monkey-patched, replacing the standard os implementation with an in-memory version:

package example_test

import (
	"testing"
	"example.com/example"
	"github.com/echocrow/osa"
)

func TestExample(t *testing.T) {
	// Monkey-patch virtual OS at the start of the test.
	_, reset := vos.Patch()
	defer reset()

	// Test like you normally would, e.g.:
	got := example.Example()
	if !got.MatchString("my-data") {
		t.Fatal(`¯\_(ツ)_/¯`)
	}
}

If you need to call os methods during the test, the patch function of the vos package also returns the virtual, patched os abstraction. Combine it with osa/testos to more quickly initialize file setups during testing:

func TestAnotherExample(t *testing.T) {
	// Monkey-patch and get virtual OS implementation.
	os, reset := vos.Patch()
	defer reset()

	// Set up files & directories, e.g.:
	userCfgDir, err := os.UserConfigDir()
	require.NoError(t, err)
	cfgDir := testos.Join(userCfgDir, "my-app")
	testos.RequireMkdirAll(t, os, testos.Join(cfgDir, "subdir", "deepdir"))
	testos.RequireWrite(t, os, testos.Join(cfgDir, "my-config"), "my-data")

	// ...

	// Test expected vs actual file setup results.
	wantFile := testos.Join(cfgDir, "expected-file")
	testos.AssertFileData(t, os, wantFile, "expected-contents")
}

API Documentation

Documentation

Overview

Code generated by osa/gen. DO NOT EDIT.

Package osa provides abstractions over various OS-related operations.

Here is a simple example of how to use this package:

import (
	os "github.com/echocrow/osa"
)

data, err := os.ReadFile("file.go") // Use "os" as usual.
if err != nil {
	log.Fatal(err)
}

Note: This package only supports a subset of functions and variables of the actual os standard library package.

Index

Constants

This section is empty.

Variables

View Source
var (
	Stdin  io.Reader = stdin{}
	Stdout io.Writer = stdout{}
	Stderr io.Writer = stderr{}
)

Stdin, Stdout, and Stderr are readers and writers for the standard input, standard output, and standard error streams.

Functions

func Exit

func Exit(code int)

Exit causes the current program to exit with the given status code.

func Getwd

func Getwd() (dir string, err error)

Getwd returns a rooted path name corresponding to the current directory.

func IsExist

func IsExist(err error) bool

IsExist returns a boolean indicating whether the error is known to report that a file or directory already exists.

func IsNotExist

func IsNotExist(err error) bool

IsNotExist returns a boolean indicating whether the error is known to report that a file or directory does not exist.

func IsPathSeparator

func IsPathSeparator(c uint8) bool

IsPathSeparator reports whether c is a directory separator character.

func Mkdir

func Mkdir(name string, perm FileMode) error

Mkdir creates a new directory.

func MkdirAll

func MkdirAll(name string, perm FileMode) error

MkdirAll creates a directory named path, along with any necessary parents.

func MkdirTemp

func MkdirTemp(dir, pattern string) (string, error)

MkdirTemp creates a new temporary directory in the directory dir and returns the pathname of the new directory.

func Open

func Open(name string) (fs.File, error)

Open opens the named file.

func Patch

func Patch(o I) func()

Patch monkey-patches the OS abstraction and returns a restore function.

BUG(echocrow): Patch is not yet thread-safe.

BUG(echocrow): Calling Patch multiple times before resetting may result in incomplete resets when reset funcs are not invoked in reverse order.

func PathSeparator

func PathSeparator() uint8

PathSeparator returns the directory separator character.

func ReadFile

func ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns the contents.

func Remove

func Remove(name string) error

Remove removes the named file or empty directory.

func RemoveAll

func RemoveAll(path string) error

RemoveAll removes path and any children it contains

func Rename

func Rename(oldpath, newpath string) error

Rename renames (moves) oldpath to newpath.

func UserCacheDir

func UserCacheDir() (string, error)

UserCacheDir returns the default directory to use for cached data.

func UserConfigDir

func UserConfigDir() (string, error)

UserConfigDir returns the default directory to use for configuration data.

func UserHomeDir

func UserHomeDir() (string, error)

UserHomeDir returns the current user's home directory.

func WriteFile

func WriteFile(name string, data []byte, perm FileMode) error

WriteFile writes data to the named file, creating it if necessary.

Types

type DirEntry

type DirEntry = fs.DirEntry

A DirEntry is an entry read from a directory.

func ReadDir

func ReadDir(name string) ([]DirEntry, error)

ReadDir reads the named directory and returns all its directory entries sorted by filename.

type FileInfo

type FileInfo = fs.FileInfo

A FileInfo describes a file and is returned by Stat and Lstat.

func Stat

func Stat(name string) (FileInfo, error)

Lstat returns a FileInfo describing the named file.

type FileMode

type FileMode = fs.FileMode

A FileMode represents a file's mode and permission bits.

type I

type I interface {
	// Open opens the named file.
	Open(name string) (fs.File, error)
	// Lstat returns a FileInfo describing the named file.
	Stat(name string) (FileInfo, error)
	// IsExist returns a boolean indicating whether the error is known to report
	// that a file or directory already exists.
	IsExist(err error) bool
	// IsNotExist returns a boolean indicating whether the error is known to
	// report that a file or directory does not exist.
	IsNotExist(err error) bool
	// PathSeparator returns the directory separator character.
	PathSeparator() uint8
	// IsPathSeparator reports whether c is a directory separator character.
	IsPathSeparator(c uint8) bool
	// Mkdir creates a new directory.
	Mkdir(name string, perm FileMode) error
	// MkdirAll creates a directory named path, along with any necessary parents.
	MkdirAll(name string, perm FileMode) error
	// MkdirTemp creates a new temporary directory in the directory dir and
	// returns the pathname of the new directory.
	MkdirTemp(dir, pattern string) (string, error)
	// ReadDir reads the named directory and returns all its directory entries
	// sorted by filename.
	ReadDir(name string) ([]DirEntry, error)
	// WriteFile writes data to the named file, creating it if necessary.
	WriteFile(name string, data []byte, perm FileMode) error
	// ReadFile reads the named file and returns the contents.
	ReadFile(name string) ([]byte, error)
	// Rename renames (moves) oldpath to newpath.
	Rename(oldpath, newpath string) error
	// Remove removes the named file or empty directory.
	Remove(name string) error
	// RemoveAll removes path and any children it contains
	RemoveAll(path string) error
	// Getwd returns a rooted path name corresponding to the current directory.
	Getwd() (dir string, err error)
	// UserCacheDir returns the default directory to use for cached data.
	UserCacheDir() (string, error)
	// UserConfigDir returns the default directory to use for configuration data.
	UserConfigDir() (string, error)
	// UserHomeDir returns the current user's home directory.
	UserHomeDir() (string, error)
	// Exit causes the current program to exit with the given status code.
	Exit(code int)
	// Stdio returns IO readers and writers for Stdin, Stdout, and Stderr.
	Stdio
}

Interface I describes available OS methods on the OS abstraction.

func Current

func Current() I

Current returns the current OS abstraction implementation.

func Default

func Default() I

Default returns the standard OS abstraction implementation.

type PathError

type PathError = fs.PathError

PathError records an error and the operation and file path that caused it.

type Stdio

type Stdio interface {
	// Stdin returns IO reader for Stdin.
	Stdin() io.Reader
	// Stdout returns IO writer for Stdout.
	Stdout() io.Writer
	// Stderr returns IO writer for Stderr.
	Stderr() io.Writer
}

Stdio describes a set of functions that return IO readers or writers for Stdin, Stdout, and Stderr.

Notes

Bugs

  • Patch is not yet thread-safe.

  • Calling Patch multiple times before resetting may result in incomplete resets when reset funcs are not invoked in reverse order.

Directories

Path Synopsis
Package main generates simple osa wrapper implementations.
Package main generates simple osa wrapper implementations.
Code generated by osa/gen.
Code generated by osa/gen.
Package testos provides utilities for common OS assert/require test operations.
Package testos provides utilities for common OS assert/require test operations.
Package testosa provides tests for OSA implementations.
Package testosa provides tests for OSA implementations.
Package vos provides a basic virtual OS abstraction implementation.
Package vos provides a basic virtual OS abstraction implementation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL