# V3020 test_unhandled_effect

URL: /docs/errors/V3020
Markdown: /docs/errors/V3020.md

> Tests run under deterministic default handlers for Clock, Random, Env, Console and Log (design §5.8).

An error from the `effect` phase. `sakura explain V3020` prints this explanation offline.

Tests run under deterministic default handlers for `Clock`, `Random`, `Env`, `Console` and
`Log` (design §5.8). Any other effect used in a test must be handled inside the test with
`with`, usually by a fake handler from std or one the test module declares.

Wrong:

```sakura
effect Db { fn count() -> Int }
test "counts rows" { expect_eq(Db.count(), 0) }
```

Fixed:

```sakura
fn empty_db() -> Handler<Db> { handler Db { fn count() { 0 } } }
test "counts rows" { with empty_db() { expect_eq(Db.count(), 0) } }
```

## Wrong program [#wrong-program]

[`compiler/tests/ui/V3020_test_unhandled_effect.sakura`](https://github.com/icantcodefyi/sakuralang/blob/master/compiler/tests/ui/V3020_test_unhandled_effect.sakura), which the compiler's ui suite runs through `sakura check`:

```sakura
effect Db {
  fn count() -> Int
}

test "counts rows" { expect_eq(Db.count(), 0) }
```

`sakura check --json` reports this record (pretty-printed; `$DIR` is the fixture's directory):

```json
{
  "schema_version": "1.0",
  "kind": "diagnostic",
  "id": "d:e91988b019622147",
  "code": "V3020",
  "severity": "error",
  "phase": "effect",
  "message": "test uses `Db` without a handler; install one with `with` (std ships fake handlers for its own effects)",
  "snapshot": "sha256:$SNAPSHOT",
  "symbol_id": "main::V3020_test_unhandled_effect::test:counts rows",
  "spans": [
    {
      "uri": "file://$DIR/V3020_test_unhandled_effect.sakura",
      "content_hash": "sha256:c7c8d39e5ec232c63875fbbb369da28bf275c4e6a4ba8b50111740b0eb0a9a4a",
      "start_byte": 74,
      "end_byte": 87,
      "role": "primary"
    },
    {
      "uri": "file://$DIR/V3020_test_unhandled_effect.sakura",
      "content_hash": "sha256:c7c8d39e5ec232c63875fbbb369da28bf275c4e6a4ba8b50111740b0eb0a9a4a",
      "start_byte": 100,
      "end_byte": 110,
      "role": "cause",
      "label": "`Db.count` performs `Db` here"
    }
  ],
  "related_ids": [],
  "expected": {
    "render": "{Clock, Console, Env, Log, Random, Test}",
    "row": {
      "labels": [
        {
          "effect": "std::Clock",
          "args": []
        },
        {
          "effect": "std::Console",
          "args": []
        },
        {
          "effect": "std::Env",
          "args": []
        },
        {
          "effect": "std::Log",
          "args": []
        },
        {
          "effect": "std::Random",
          "args": []
        },
        {
          "effect": "std::Test",
          "args": []
        }
      ],
      "tail": null
    }
  },
  "actual": {
    "render": "{Db, Test}",
    "row": {
      "labels": [
        {
          "effect": "std::Test",
          "args": []
        },
        {
          "effect": "main::Db",
          "args": []
        }
      ],
      "tail": null
    }
  },
  "obligation": null,
  "counterexample": null,
  "explanation_uri": "sakura://explain/V3020",
  "fixes": []
}
```

## Fixed program [#fixed-program]

[`compiler/tests/ui/V3020_test_unhandled_effect.fixed.sakura`](https://github.com/icantcodefyi/sakuralang/blob/master/compiler/tests/ui/V3020_test_unhandled_effect.fixed.sakura), which `sakura check` accepts with no diagnostics:

```sakura
effect Db {
  fn count() -> Int
}

fn empty_db() -> Handler<Db> {
  handler Db {
    fn count() { 0 }
  }
}

test "counts rows" { with empty_db() { expect_eq(Db.count(), 0) } }
```
