Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

Commit

Permalink
feat: partial decoder tests
Browse files Browse the repository at this point in the history
  • Loading branch information
baetheus committed Apr 22, 2021
1 parent 832669d commit b1d7aa8
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 82 deletions.
18 changes: 14 additions & 4 deletions examples/semigroup.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import * as S from "../semigroup.ts";

export type T1 = {
one: string,
two: number,
}
one: string;
two: number;
};

const mySemi = S.getStructSemigroup
const mySemi = S.getStructSemigroup<T1>({
one: S.getFirstSemigroup(),
two: S.semigroupProduct,
});

const t1: T1 = { one: "Hello", two: 10 };
const t2: T1 = { one: "World", two: 12 };

const r1 = mySemi.concat(t1)(t2);

console.log(r1);
97 changes: 54 additions & 43 deletions schemable/decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,24 +144,27 @@ const toForest: (e: Failure) => ReadonlyArray<T.Tree<string>> = Free.fold(
export const draw = (e: Failure): string =>
toForest(e).map(T.drawTree).join("\n");

export const extract = <A>(decoded: Decoded<A>) =>
pipe(decoded, E.mapLeft(draw));

/*******************************************************************************
* Modules
******************************************************************************/

export const UnknownSchemable: S.UnknownSchemable<URI> = {
unknown: () => fromGuard(G.unknown(), "unknown"),
unknown: () => fromGuard(G.unknown, "unknown"),
};

export const StringSchemable: S.StringSchemable<URI> = {
string: () => fromGuard(G.string(), "string"),
string: () => fromGuard(G.string, "string"),
};

export const NumberSchemable: S.NumberSchemable<URI> = {
number: () => fromGuard(G.number(), "number"),
number: () => fromGuard(G.number, "number"),
};

export const BooleanSchemable: S.BooleanSchemable<URI> = {
boolean: () => fromGuard(G.boolean(), "boolean"),
boolean: () => fromGuard(G.boolean, "boolean"),
};

export const LiteralSchemable: S.LiteralSchemable<URI> = {
Expand Down Expand Up @@ -220,21 +223,19 @@ export const ArraySchemable: S.ArraySchemable<URI> = {
export const TupleSchemable: S.TupleSchemable<URI> = {
tuple: (...components) =>
// deno-lint-ignore no-explicit-any
(u: unknown): any => {
if (!Array.isArray(u) || u.length !== components.length) {
return failure(u, `tuple of length ${components.length}`);
}
return pipe(
u,
traverseArray((uu, i) =>
pipe(
components[i](uu),
E.mapLeft((e) => make.index(i, "required", e)),
)
),
E.mapLeft((e) => make.wrap("cannot decode tuple", e)),
);
},
(u: unknown): any =>
Array.isArray(u) && u.length === components.length
? pipe(
u,
traverseArray((uu, i) =>
pipe(
components[i](uu),
E.mapLeft((e) => make.index(i, "required", e)),
)
),
E.mapLeft((e) => make.wrap("cannot decode tuple", e)),
)
: failure(u, `tuple of length ${components.length}`),
};

export const StructSchemable: S.StructSchemable<URI> = {
Expand All @@ -258,9 +259,9 @@ export const StructSchemable: S.StructSchemable<URI> = {
export const PartialSchemable: S.PartialSchemable<URI> = {
partial: (properties) =>
// deno-lint-ignore no-explicit-any
(u: unknown): any => {
if (isRecord(u)) {
return pipe(
(u: unknown): any =>
isRecord(u)
? pipe(
properties,
// deno-lint-ignore no-explicit-any
traverseRecord((decoder: Decoder<any>, i) =>
Expand All @@ -271,10 +272,8 @@ export const PartialSchemable: S.PartialSchemable<URI> = {
)
),
E.mapLeft((e) => make.wrap("cannot decode partial", e)),
);
}
return failure(u, "struct");
},
)
: failure(u, "struct"),
};

export const IntersectSchemable: S.IntersectSchemable<URI> = {
Expand Down Expand Up @@ -332,20 +331,32 @@ export const Schemable: S.Schemable<URI> = {
...LazySchemable,
};

export const {
unknown,
string,
number,
boolean,
literal,
nullable,
undefinable,
record,
array,
tuple,
struct,
partial,
intersect,
union,
lazy,
} = Schemable;
export const unknown = Schemable.unknown();

export const string = Schemable.string();

export const number = Schemable.number();

export const boolean = Schemable.boolean();

export const literal = Schemable.literal;

export const nullable = Schemable.nullable;

export const undefinable = Schemable.undefinable;

export const record = Schemable.record;

export const array = Schemable.array;

export const tuple = Schemable.tuple;

export const struct = Schemable.struct;

export const partial = Schemable.partial;

export const intersect = Schemable.intersect;

export const union = Schemable.union;

export const lazy = Schemable.lazy;
46 changes: 29 additions & 17 deletions schemable/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,32 @@ export const Schemable: S.Schemable<URI> = {
* Pipeables
******************************************************************************/

export const {
unknown,
string,
number,
boolean,
literal,
undefinable,
nullable,
record,
array,
tuple,
struct,
partial,
intersect,
union,
lazy,
} = Schemable;
export const unknown = Schemable.unknown();

export const string = Schemable.string();

export const number = Schemable.number();

export const boolean = Schemable.boolean();

export const literal = Schemable.literal;

export const nullable = Schemable.nullable;

export const undefinable = Schemable.undefinable;

export const record = Schemable.record;

export const array = Schemable.array;

export const tuple = Schemable.tuple;

export const struct = Schemable.struct;

export const partial = Schemable.partial;

export const intersect = Schemable.intersect;

export const union = Schemable.union;

export const lazy = Schemable.lazy;
53 changes: 53 additions & 0 deletions testing/schemable/decoder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

import * as D from "../../schemable/decoder.ts";
import * as G from "../../schemable/guard.ts";
import * as DE from "../../schemable/decode_error.ts";
import * as E from "../../either.ts";

Deno.test("Decoder success", () => {
assertEquals(D.success(1), E.right(1));
});

Deno.test("Decoder failure", () => {
assertEquals(D.failure(1, "1"), E.left(DE.make.leaf(1, "1")));
});

Deno.test("Decoder fromGuard", () => {
const decoder = D.fromGuard(G.number, "number");
assertEquals(decoder(0), D.success(0));
assertEquals(decoder(true), D.failure(true, "number"));
});

Deno.test("Decoder unknown", () => {
assertEquals(D.unknown(1), D.success(1));
});

Deno.test("Decoder string", () => {
assertEquals(D.string("asdf"), D.success("asdf"));
assertEquals(D.string(1), D.failure(1, "string"));
});

Deno.test("Decoder number", () => {
assertEquals(D.number(1), D.success(1));
assertEquals(D.number(false), D.failure(false, "number"));
});

Deno.test("Decoder boolean", () => {
assertEquals(D.boolean(true), D.success(true));
assertEquals(D.boolean(false), D.success(false));
assertEquals(D.boolean(0), D.failure(0, "boolean"));
});

Deno.test("Decoder literal", () => {
const literal = D.literal(1, 2, 3);
assertEquals(literal(1), D.success(1));
assertEquals(literal(false), D.failure(false, "literal 1, 2, or 3"));
});

Deno.test("Decoder nullable", () => {
const decoder = D.undefinable(D.number);
assertEquals(decoder(0), D.success(0));
assertEquals(decoder(undefined), D.success(undefined));
// assertEquals(decoder(true), D.failure(true, ""));
});
36 changes: 18 additions & 18 deletions testing/schemable/guard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import * as G from "../../schemable/guard.ts";
import { pipe } from "../../fns.ts";

Deno.test("Guard unknown", () => {
assertEquals(G.unknown()(1), true);
assertEquals(G.unknown(1), true);
});

Deno.test("Guard string", () => {
assertEquals(G.string()("asdf"), true);
assertEquals(G.string()(1), false);
assertEquals(G.string("asdf"), true);
assertEquals(G.string(1), false);
});

Deno.test("Guard number", () => {
assertEquals(G.number()("asdf"), false);
assertEquals(G.number()(1), true);
assertEquals(G.number("asdf"), false);
assertEquals(G.number(1), true);
});

Deno.test("Guard boolean", () => {
assertEquals(G.boolean()(true), true);
assertEquals(G.boolean()(false), true);
assertEquals(G.boolean()("asdf"), false);
assertEquals(G.boolean(true), true);
assertEquals(G.boolean(false), true);
assertEquals(G.boolean("asdf"), false);
});

Deno.test("Guard literal", () => {
Expand All @@ -46,39 +46,39 @@ Deno.test("Guard nullable", () => {
});

Deno.test("Guard record", () => {
const guard = G.record(G.number());
const guard = G.record(G.number);
assertEquals(guard({}), true);
assertEquals(guard({ "one": 1 }), true);
assertEquals(guard({ "one": false }), false);
assertEquals(guard(1), false);
});

Deno.test("Guard array", () => {
const guard = G.array(G.boolean());
const guard = G.array(G.boolean);
assertEquals(guard(true), false);
assertEquals(guard([]), true);
assertEquals(guard([true]), true);
assertEquals(guard(["asdf"]), false);
});

Deno.test("Guard tuple", () => {
const guard = G.tuple(G.literal("Left", "Right"), G.number());
const guard = G.tuple(G.literal("Left", "Right"), G.number);
assertEquals(guard(["Left", 1]), true);
assertEquals(guard(["Right", 1]), true);
assertEquals(guard(false), false);
assertEquals(guard(["Left"]), false);
});

Deno.test("Guard struct", () => {
const guard = G.struct({ one: G.number() });
const guard = G.struct({ one: G.number });
assertEquals(guard({}), false);
assertEquals(guard(1), false);
assertEquals(guard({ one: false }), false);
assertEquals(guard({ one: 1 }), true);
});

Deno.test("Guard partial", () => {
const guard = G.partial({ one: G.number() });
const guard = G.partial({ one: G.number });
assertEquals(guard({}), true);
assertEquals(guard(1), false);
assertEquals(guard({ one: false }), false);
Expand All @@ -87,8 +87,8 @@ Deno.test("Guard partial", () => {

Deno.test("Guard intersect", () => {
const guard = pipe(
G.struct({ two: G.boolean() }),
G.intersect(G.struct({ one: G.number() })),
G.struct({ two: G.boolean }),
G.intersect(G.struct({ one: G.number })),
);
assertEquals(guard({}), false);
assertEquals(guard(1), false);
Expand All @@ -99,8 +99,8 @@ Deno.test("Guard intersect", () => {

Deno.test("Guard union", () => {
const guard = pipe(
G.number(),
G.union(G.boolean()),
G.number,
G.union(G.boolean),
);
assertEquals(guard(null), false);
assertEquals(guard("asdf"), false);
Expand All @@ -109,7 +109,7 @@ Deno.test("Guard union", () => {
});

Deno.test("Guard lazy", () => {
const guard = G.lazy("One", G.number);
const guard = G.lazy("One", () => G.number);
assertEquals(guard(1), true);
assertEquals(guard(true), false);
});

0 comments on commit b1d7aa8

Please sign in to comment.