From c00025f2fd1e6d2d9848f4bb3e056b3fffb51024 Mon Sep 17 00:00:00 2001
From: Erick Sosa Garcia <ericksosagarcias@gmail.com>
Date: Mon, 20 Jul 2020 16:14:56 -0400
Subject: [PATCH 1/5] add: more numerical assertion methods added

---
 README.md     | 104 ++++++++++++++++-----------
 src/merlin.ts | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+), 42 deletions(-)

diff --git a/README.md b/README.md
index f7358b4..1560725 100644
--- a/README.md
+++ b/README.md
@@ -22,39 +22,30 @@ Merlin is a [Jest](https://jestjs.io/en/)-inspired testing framework for deno.
 
 ### All Matchers
 
-- `testEqual(label: string, config)`_Compare two values and throws an error if the expect and toBe are not equal._
-
-- `testNotEqual(label: string, config)`_Compare two values and throws an error if the expect and notBe are equal._
-
-- `evalEquals(testEqual[])` _evaluate multiple equality tests in an array. If the data is not the same it throws an error._
-
-- `fetchEqual(label: string, config)` _evaluate if two values ​​are equal. If the request data is not the same as expected, it throws an error._
-
-- `arrayContains(label: string, config)`_evaluates that the array contains an especific data. if the array does not contain the data it throws an error._
-
-- `stringContains(label: string, config)`_evaluates if a string contains an especific word. if the string does not contain the word it throws an error._
-
-- `beNull(label: string, config)` _evaluates if a data is null._
-
-- `beFalsy(label: string, config)`_evaluates if a data is a falsy value._
-
-- `beTruthy(label: string, config)`_evaluates if a data is a truthy value._
-
-- `isBigInt(label: string, config)`_evaluates if a data is a bigInt value type._
-
-- `isZero(label: string, config)`_evaluates if a data is a Zero_
-
-- `isNaN(label: string, config)`_evaluates if a data is NaN value._
-
-- `sameLength(label: string, config)`_evaluates if data has a especific length_
-
-- `testRegExp(label: string, config)`_evaluates if a regular expression match_
-
-- `isFunction(label: string, config)` _evaluates if a data is a function_
-
-- `isSymbol(label: string, config)`_evaluates if a data is a symbol_
-
-- `isUndefined(label: string, config)`_evaluates if a data is undefined_
+- `testEqual(label: string, config)` Compare two values and throws an error if the expect and toBe are not equal
+- `testNotEqual(label: string, config)` Compare two values and throws an error if the expect and notBe are equal
+- `evalEquals(testEqual[])` evaluate multiple equality tests in an array. If the data is not the same it throws an error
+- `fetchEqual(label: string, config)` evaluate if two values ​​are equal. If the request data is not the same as expected, it throws an error
+- `arrayContains(label: string, config)` evaluates that the array contains an especific data. if the array does not contain the data it throws an error
+- `stringContains(label: string, config)` evaluates if a string contains an especific word. if the string does not contain the word it throws an error
+- `beNull(label: string, config)` evaluates if a data is null
+- `beFalsy(label: string, config)` evaluates if a data is a falsy value
+- `beTruthy(label: string, config)` evaluates if a data is a truthy value
+- `isBigInt(label: string, config)` evaluates if a data is a bigInt value type
+- `isZero(label: string, config)` evaluates if a data is a Zero
+- `isNaN(label: string, config)` evaluates if a data is NaN value
+- `sameLength(label: string, config)` evaluates if data has a especific length
+- `testRegExp(label: string, config)` evaluates if a regular expression match
+- `isFunction(label: string, config)` evaluates if a data is a function
+- `isSymbol(label: string, config)` evaluates if a data is a symbol
+- `isUndefined(label: string, config)` evaluates if a data is undefined
+- `testSame(label: string, config)`
+- `testGreaterOrEqual(label: string, config)`
+- `testGreater(label: string, config)`
+- `testLess(label: string, config)`
+- `testLessOrEqual(label: string, config)`
+- `testInstanceOf(label: string, config)`
+- `testFloat(label: string, config)`
 
 ### Basic Use
 
@@ -108,7 +99,7 @@ all assertions have parameters that they can receive, these parameters can chang
 - `Resources (optional)` receives a boolean, terminates all asynchronous processes that interact with the system. by default is `true`.
 - `only (optional)` receives a boolean, only tests that have `only in true` will be executed, the rest will not run.
 
-## about resources and ops sanitizers
+### about resources and ops sanitizers
 
 Certain actions in Deno create resources in the resource table . These resources should be closed after you are done using them.
 
@@ -126,13 +117,14 @@ async function writeSomething(): Promise<string> {
 }
 
 test.testEqual("Leak resources test", {
-  expect:() => "test",
-  toBe:() =>writeSomething(),
+  expect: async () => await writeSomething(),
+  toBe: () => "test",
   only: true,
   Ops: false,
-  Resources: false
+  Resources: false,
 });
 ```
+
 ```sh
 deno test
 
@@ -140,6 +132,7 @@ test Leak resources test ... ok (5ms)
 
 test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
 ```
+
 ### Multiple tests
 
 `example.test.ts`
@@ -263,16 +256,43 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
 ```
 
 ### testRegExp
+
 ```typescript
-test.testRegExp("regEx match",{
-  expect:()=> "https://google.com",
-  toBe:()=> new RegExp("^https?:\/\/[a-z.]+\.com$"),
-})
+test.testRegExp("regEx match", {
+  expect: () => "https://google.com",
+  toBe: () => new RegExp("^https?://[a-z.]+.com$"),
+});
 ```
+
 ```sh
 deno test
 
 test regEx match ... ok (6ms)
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (342ms)
-```
\ No newline at end of file
+```
+
+### Usin async code.
+
+you can use asynchronous code by adding `async` in `expect`, `toBe` and `value` functions.
+
+example
+
+```typescript
+const test = new Merlin();
+
+test.testEqual("get error 404", {
+  async expect() {
+    const response = await fetch("https://deno.land/std/example/examples.ts");
+
+    const data = response.text();
+
+    return data;
+  },
+  toBe() {
+    return "404: Not Found";
+  },
+});
+```
+
+> **Note**: all the methods of the merlin class support asyn function since they have top level await
diff --git a/src/merlin.ts b/src/merlin.ts
index e2ee9f2..7da8a56 100644
--- a/src/merlin.ts
+++ b/src/merlin.ts
@@ -455,4 +455,195 @@ export class Merlin {
       sanitizeResources: Resources,
     });
   }
+
+  /**
+   * expect the two values ​​to be strictly equal
+   */
+  public testSame(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assertStrictEquals(await expect(), await toBe(), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  /**
+   * expect the expected value to be greater than or equal
+   */
+  public testGreaterOrEqual(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assert((await expect()) >= (await toBe()), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  /**
+   * expect the expected value to be greater
+   */
+  public testGreater(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assert((await expect()) > (await toBe()), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  /**
+   * expect the expected value to be less.
+   */
+  public testLess(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assert((await expect()) < (await toBe()), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  /**
+   * expect the expected value to be less or equal.
+   */
+  public testLessOrEqual(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assert((await expect()) <= (await toBe()), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  /**
+   * expect both values ​​to be instances of the same class
+   */
+  public testInstanceOf(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        assert((await expect()) instanceof (await toBe()), message);
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
+
+  public testFloat(
+    label: string,
+    {
+      expect,
+      toBe,
+      Ops = true,
+      Resources = true,
+      ignore,
+      message,
+      only,
+      strict,
+    }: testConfig
+  ) {
+    this.Test({
+      name: label,
+      fn: async () => {
+        if (strict) {
+          assertStrictEquals(await expect(), await toBe(), message);
+        } else {
+          assertEquals(await expect(), await toBe(), message);
+        }
+      },
+      ignore,
+      only,
+      sanitizeOps: Ops,
+      sanitizeResources: Resources,
+    });
+  }
 }

From 9c03f1689dfdf36ae9db3319f2f350d69c1abad6 Mon Sep 17 00:00:00 2001
From: Erick Sosa Garcia <ericksosagarcias@gmail.com>
Date: Tue, 21 Jul 2020 13:13:15 -0400
Subject: [PATCH 2/5] add: pretty logs in benchmarks

---
 deps.ts      |  1 +
 src/maven.ts | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/deps.ts b/deps.ts
index f2daf12..c2f8df8 100644
--- a/deps.ts
+++ b/deps.ts
@@ -6,5 +6,6 @@
  *
  */
 
+export * from "https://deno.land/x/pretty_benching@v0.1.2/mod.ts";
 export * from "https://deno.land/std/testing/asserts.ts";
 export * from "https://deno.land/std/testing/bench.ts";
diff --git a/src/maven.ts b/src/maven.ts
index 10dd17e..91358e7 100644
--- a/src/maven.ts
+++ b/src/maven.ts
@@ -11,6 +11,8 @@ import {
   runBenchmarks,
   BenchmarkResult,
   BenchmarkRunOptions,
+  prettyBenchmarkProgress,
+  prettyBenchmarkResult,
 } from "../deps.ts";
 
 interface Bench {
@@ -40,10 +42,21 @@ export class Maven {
 
   public async runBench(config?: BenchmarkRunOptions) {
     this.config = config as BenchmarkRunOptions;
-    return runBenchmarks(config);
+    return runBenchmarks(config, prettyBenchmarkProgress());
   }
 
   public async success() {
     return await this.runBench(this.config);
   }
+
+  public Result(graphBars = 5) {
+    return prettyBenchmarkResult({
+      parts: {
+        extraMetrics: true,
+        graph: true,
+        threshold: true,
+        graphBars,
+      },
+    });
+  }
 }

From 997c822be21cb5e5875a2596cb99dea5de2c4b40 Mon Sep 17 00:00:00 2001
From: Erick Sosa Garcia <ericksosagarcias@gmail.com>
Date: Tue, 21 Jul 2020 15:50:12 -0400
Subject: [PATCH 3/5] add: cli tool for maven and merlin

---
 cli.ts       | 37 +++++++++++++++++++++++++++++++++++++
 deps.ts      |  2 +-
 src/maven.ts | 33 +++++++++++++++++++++++++++++++--
 3 files changed, 69 insertions(+), 3 deletions(-)
 create mode 100644 cli.ts

diff --git a/cli.ts b/cli.ts
new file mode 100644
index 0000000..68b4da1
--- /dev/null
+++ b/cli.ts
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) Crew Dev.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ */
+
+import { colors } from "./deps.ts";
+
+async function main() {
+  const [command, ...args] = Deno.args;
+
+  if (command === "start") {
+    const process = Deno.run({
+      cmd: ["deno", "test", "--allow-hrtime", ...args],
+    });
+
+    if ((await process.status()).success) {
+      Deno.close(process.rid);
+    } else {
+      Deno.close(process.rid);
+      throw new Error(colors.red("something went wrong trying to run the test"))
+        .message;
+    }
+  } else if (command === "help") {
+    console.log("help info...");
+  } else {
+    throw new Error(
+      colors.red("this command was not found, try run: merlin help")
+    ).message;
+  }
+}
+
+if (import.meta.main) {
+  await main();
+}
diff --git a/deps.ts b/deps.ts
index c2f8df8..298e3da 100644
--- a/deps.ts
+++ b/deps.ts
@@ -5,7 +5,7 @@
  * LICENSE file in the root directory of this source tree.
  *
  */
-
 export * from "https://deno.land/x/pretty_benching@v0.1.2/mod.ts";
+export * as colors from "https://deno.land/std/fmt/colors.ts";
 export * from "https://deno.land/std/testing/asserts.ts";
 export * from "https://deno.land/std/testing/bench.ts";
diff --git a/src/maven.ts b/src/maven.ts
index 91358e7..8eaeec8 100644
--- a/src/maven.ts
+++ b/src/maven.ts
@@ -13,22 +13,43 @@ import {
   BenchmarkRunOptions,
   prettyBenchmarkProgress,
   prettyBenchmarkResult,
+  colors,
 } from "../deps.ts";
-
 interface Bench {
   name: string;
   steps?: number;
   fn: Function;
 }
 
+interface Thresholds {
+  [key: string]: { green: number; yellow: number };
+}
+
 export type BenchResult = BenchmarkResult;
 
 export class Maven {
   private bench = bench;
 
+  private thresholds: Thresholds = {};
+
   private config: BenchmarkRunOptions = {};
 
+  private indicators = [
+    {
+      benches: /./,
+      tableColor: colors.cyan,
+      modFn: () => "🧪",
+    },
+  ];
+
+  private runIndicator = [{ benches: /./, modFn: () => colors.green(" ==> ") }];
+
+  private addThreasholds(name: string) {
+    this.thresholds[name] = { green: 70, yellow: 90 };
+  }
+
   public Bench({ fn, name, steps = 1 }: Bench) {
+    this.addThreasholds(name);
     this.bench({
       name,
       func(bench) {
@@ -42,7 +63,13 @@ export class Maven {
 
   public async runBench(config?: BenchmarkRunOptions) {
     this.config = config as BenchmarkRunOptions;
-    return runBenchmarks(config, prettyBenchmarkProgress());
+    return runBenchmarks(
+      { silent: true, ...config },
+      prettyBenchmarkProgress({
+        indicators: this.runIndicator,
+        thresholds: this.thresholds,
+      })
+    );
   }
 
   public async success() {
@@ -51,6 +78,8 @@ export class Maven {
 
   public Result(graphBars = 5) {
     return prettyBenchmarkResult({
+      thresholds: this.thresholds,
+      indicators: this.indicators,
       parts: {
         extraMetrics: true,
         graph: true,

From d78db54ea3a736934ca3588f7625bea7bdaba7b9 Mon Sep 17 00:00:00 2001
From: Erick Sosa Garcia <ericksosagarcias@gmail.com>
Date: Tue, 21 Jul 2020 19:07:34 -0400
Subject: [PATCH 4/5] update: more description information

---
 README.md | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index 1560725..72e2beb 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ Merlin is a [Jest](https://jestjs.io/en/)-inspired testing framework for deno.
 - `testEqual(label: string, config)` Compare two values and throws an error if the expect and toBe are not equal
 - `testNotEqual(label: string, config)` Compare two values and throws an error if the expect and notBe are equal
 - `evalEquals(testEqual[])` evaluate multiple equality tests in an array. If the data is not the same it throws an error
-- `fetchEqual(label: string, config)` evaluate if two values ​​are equal. If the request data is not the same as expected, it throws an error
+- `fetchEqual(label: string, config)` evaluate if two values are equal. If the request data is not the same as expected, it throws an error
 - `arrayContains(label: string, config)` evaluates that the array contains an especific data. if the array does not contain the data it throws an error
 - `stringContains(label: string, config)` evaluates if a string contains an especific word. if the string does not contain the word it throws an error
 - `beNull(label: string, config)` evaluates if a data is null
@@ -39,13 +39,13 @@ Merlin is a [Jest](https://jestjs.io/en/)-inspired testing framework for deno.
 - `isFunction(label: string, config)` evaluates if a data is a function
 - `isSymbol(label: string, config)` evaluates if a data is a symbol
 - `isUndefined(label: string, config)` evaluates if a data is undefined
-- `testSame(label: string, config)`
-- `testGreaterOrEqual(label: string, config)`
-- `testGreater(label: string, config)`
-- `testLess(label: string, config)`
-- `testLessOrEqual(label: string, config)`
-- `testInstanceOf(label: string, config)`
-- `testFloat(label: string, config)`
+- `testSame(label: string, config)` evaluates if two values are strictly the same
+- `testGreaterOrEqual(label: string, config)` evaluates whether the expected data is greater than or equal to another
+- `testGreater(label: string, config)` evaluates whether the expected data is greater than another
+- `testLess(label: string, config)` evaluates if the expected data is less than another
+- `testLessOrEqual(label: string, config)` evaluates if the expected data is less than or equal to another
+- `testInstanceOf(label: string, config)` evaluates that one object is an instance of another
+- `testFloat(label: string, config)` evaluates if two decimal numbers are equal
 
 ### Basic Use
 

From bc4aed7ce73df6da75f3fc061a9a9ceeef30caa7 Mon Sep 17 00:00:00 2001
From: Erick Sosa Garcia <ericksosagarcias@gmail.com>
Date: Tue, 21 Jul 2020 19:51:16 -0400
Subject: [PATCH 5/5] add: Maven use information

---
 README.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/README.md b/README.md
index 72e2beb..7f97764 100644
--- a/README.md
+++ b/README.md
@@ -296,3 +296,80 @@ test.testEqual("get error 404", {
 ```
 
 > **Note**: all the methods of the merlin class support asyn function since they have top level await
+
+## Create benchmarks using Maven
+
+Maven is a benchmark tool for deno included in Merlin.
+
+It's easy to use. `example`:
+
+```typescript
+import { Maven } from "https://deno.land/x/merlin/mod.ts";
+
+const benchmark = new Maven();
+
+benchmark.Bench({
+  name: "Sorting arrays",
+  fn: () => {
+    new Array(10000).fill(Math.random()).sort();
+  },
+  steps: 1000,
+});
+
+benchmark.runBench();
+```
+
+this is the terminal output
+
+![gif](https://cdn.discordapp.com/attachments/656976424778989602/735278025742221324/ezgif.com-video-to-gif.gif)
+
+### Parameters
+
+maven receives the following parameters.
+
+- `name: string` benchmark name
+- `fn(): void` function that contains the code
+- `steps: number` number of times to repeat the benchmark
+
+you can see the details at the end of the benchmark using
+
+```typescript
+import { Maven } from "https://deno.land/x/merlin/mod.ts";
+
+const benchmark = new Maven();
+
+benchmark.Bench({
+  name: "Sorting arrays",
+  fn: () => {
+    new Array(10000).fill(Math.random()).sort();
+  },
+  steps: 1000,
+});
+
+benchmark.runBench().then(benchmark.Result());
+```
+
+It has a table with the detailed values
+
+```sh
+▒▒▒▒▒▒▒▒ Benchmarking finished
+
+┌───────────────────────────────────────────────────────────────────────────────────────────┐
+│ 🧪 Benchmark name:  Sorting arrays                                                        │
+├───────────────────────┬──────────────────────────────┬────────────────────────────────────┤
+│    Total runs: 1000   │  Total time: 1099.6591 ms    │  Avg time: 1.0997 ms               │
+├───────────────────────┼────────────────────┬─────────┴───────────┬────────────────────────┤
+│    min: 0.7768 ms     │ max: 9.9867 ms     │ mean: 5.3817 ms     │ median: 0.8511 ms      │
+├───────────────────────┴────────────────────┴─────────────────────┴────────────────────────┤
+│    Thresholds:  0 ========== 70 ========== 90 ========== ∞                                │
+├───────────────────────────────┬───────────────────────────────────────────────────────────┤
+│                               │                                                           │
+│    0.7768 ms _[   965][96.5%] │========================================================   │
+│    2.6188 ms _[    33][ 3.3%] │==                                                         │
+│    4.4608 ms _[     1][ 0.1%] │=                                                          │
+│    6.3027 ms _[     0][   0%] │                                                           │
+│    8.1447 ms _[     1][ 0.1%] │=                                                          │
+│                               │                                                           │
+└───────────────────────────────┴───────────────────────────────────────────────────────────┘
+
+```