# Fakear

A module that creates fake binaries from valid configuration ( a yaml file or a dict ) and launch them in the context of your Python script, without efforts.

# Installation

```
pip install fakear
```

# Quick Start

This is a mock of a fake `ls` command, that 

```yaml
ls:
  - args:
      - dexter
    return_code: 0
    output: Omelette du Fromage
```

On Python, you can now use Fakear to fake ls behaviour and act according to our mock.

```python
>>> from subprocess import run
>>> from fakear import Fakear
>>> p = run(["ls", "dexter"])
ls: dexter: No such file or directory
>>> p.returncode
1
>>> with Fakear(cfg="fake_ls.yaml"):
...   fake_cmd = run(["ls", "dexter"])
Omelette du Fromage
>>> fake_cmd.returncode
0
```

You can use it as well in your unit test routine:

```python
from fakear import Fakear
from subprocess import check_output

def test_faked_ls(self):
    with Fakear(cfg="fake_ls.yaml"):
        proc = check_output(["ls", "dexter"])
    
    assert proc.decode() == "Omelette du fromage\n"
```

# How does it works ?

An instance handles a specific configuration file, with scenarios for one or
multiple commands to fake.

By default, an instance is deactivated, meaning you can still configure it
before the fake happens

When activated:
 - The instance creates the folder that should contains the fake binaries (faked_path)
 - It builds shell scripts corresponding to all the scenarios
 - It ensures every scripts are runnable
 - It sets in os.environ["PATH"] the faked_path at first place

So, as long as the instance is activated, you can run faked commands with subprocess module.

When deactivated, the instance removes the faked_path from PATH and deletes the folder from the filesystem


# Documentation

## YAML Files

Every program mock should start with the program name as a key. Then you can describe multiple behaviours for a given set of arguments.

```yaml
__command_name__ :
  # Default output with no arguments
  - return_code: -1
    output: This is a fake program, please give the correct arguments
  # output with arguments
  - args:
    - first_arg
    - sec_arg
    return_code: 0
    output: This is an example of fake command
  # output_file with arguments
  - args:
    - first_arg
    - sec_arg
    return_code: 0
    output_file: semver.txt
__command2_name__ :
  # Default behaviour of a program generated by Fakear
```

You can use those options to customise your fake program:

  - **args (Optionna̦l)** : a list of positionnal arguments that invoke this fake output
  - **return_code** : the return code when the program exits
  - **output**: The raw data to output when you invoke the program with these args
  - **output_file**: The path of a file containing the output to show

Notice that if you mention no args to your list in a subcommand, it overrides the default behaviour of your fake program.

Also, you have to set either **output** or **output_file** keys in the same subcommand.
Otherwise, it should throw an error.


## API

You can use Fakear in two ways:

- as an instance:
```py
>>> fakear = Fakear(cfg="path_of_a_valid.yml")
>>> fakear.enable()
# DO THINGS
>>> fakear.disable()
```
A Fakear instance can be manually enabled or disabled with the correct methods

- as a Context Manager (recommended):

```python
with Fakear(cfg="fake_ls.yml"):
    # DO THINGS
```
With the context manager, enable et disable are handled automatically, and you can set the fake path at instanciation

### Init variables
```py
Fakear(cfg="/path/cfg.yaml", raw=cfg_data, path="/tmp/bin")
```

- cfg: Path of the config file to use
- raw: Python dict
- path: Path for fake binaries

You can use either cfg or raw but not both of them, as it should overlap scenarios of the same command and create undefined behaviour.

### Available Methods

- enable() : Activate the instance
- deactivate() : Deactivate the instance
- set_path(path: str) : Sets a new path for faked commands. It must be absolute. You can't modify path when the instance is activated


# Contribute

Feel free to open an issue on this repository.