Skip to content

Commit

Permalink
Merge pull request #172 from drashland/feat/arg-expectations
Browse files Browse the repository at this point in the history
feat(fake/mock): allow pre-programming methods with callbacks
  • Loading branch information
crookse authored Jan 30, 2023
2 parents 859f800 + 474eba0 commit 73ec134
Show file tree
Hide file tree
Showing 24 changed files with 1,343 additions and 195 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/master.yml → .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: master
name: Main

on:
pull_request:
Expand Down Expand Up @@ -31,7 +31,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
# We only support until EOL
# See https://nodejs.org/en/about/releases/
node: ['14', '16', '17', '18']
node: ['14', '16', '18']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
Expand Down
24 changes: 0 additions & 24 deletions .github/workflows/pre_release.yml

This file was deleted.

12 changes: 0 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,3 @@ jobs:
run: yarn publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

publish-egg:
runs-on: ubuntu-latest
steps:
- name: Notify the castle about this release
run: |
curl -X POST \
-u "${{ secrets.CI_USER_NAME }}:${{ secrets.CI_USER_PAT }}" \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Content-Type: application/json" \
--data '{"event_type": "release", "client_payload": { "repo": "rhum", "module": "rhum", "version": "${{ github.ref }}" }}' \
https://api.github.com/repos/drashland/castle/dispatches
3 changes: 2 additions & 1 deletion console/build_esm_lib
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash

# This script only exists to run Deno in different OSs.
(
deno run --allow-read --allow-run --allow-write ./console/build_esm_lib.ts
deno run --allow-read --allow-run --allow-write ./console/build_esm_lib.ts $@
)
148 changes: 120 additions & 28 deletions console/build_esm_lib.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,89 @@
/**
* @TODO(crookse) This can probably use Line. Line wouldn't necessariliy be a
* dependency of the lib. It would be a dependency of the build process.
*
* This script takes TypeScript files that follow Deno's requirements of (e.g.,
* `import` statements require `.ts` extensions) and converts them to a portable
* format that other non-Deno processes can use.
*
* For example, running `deno run -A ./console/build_esm_lib.ts ./src ./mod.ts`
* will do the following:
*
* 1. Create a directory to build the portable TypeScript code. The directory
* in this context is called the "workspace directory" and lives at
* `./tmp/conversion_workspace` directory.
* 2. Copy `./src` into the workspace directory.
* 3. Copy `./mod.ts` into the workspace directory.
* 4. Remove all `.ts` extensions from all `import` and `export` statements in
* all files in the workspace directory.
*
* Now that all `.ts` extensions are removed from the `import` and `export`
* statements, the workspace directory can be used by other processes. For
* example, `tsc` can be used on the workspace directory to compile the code
* down to a specific format like CommonJS for Node applications and a plain
* JavaScript module syntax for browser applications.
*
* @param Deno.args A list of directories and files containing TypeScript files
* that this script should convert.
*/

import { copySync, emptyDirSync, ensureDirSync, walk } from "./deps.ts";
const decoder = new TextDecoder();
const encoder = new TextEncoder();
const workspace = "./tmp/conversion_workspace";

const debug = false;
const args = Deno.args.slice();

const debug = optionEnabled("--debug");
const debugContents = optionEnabled("--debug-contents");
const workspace = optionValue("--workspace");

Promise
.resolve((() => {
createWorkspace();
logDebug(`Options:`, { debug, debugContents });
})())
.then(convertCode)
.then(() => Deno.exit(0))
.catch((error) => {
logDebug(error);
Deno.exit(1);
});

function logDebug(msg: unknown): void {
if (!debug) {
return;
/**
* Convert the code given to this script.
*/
async function convertCode(): Promise<void> {
logDebug("\nStarting .ts extension removal process.\n");

for await (const entry of walk(workspace)) {
if (!entry.isFile) {
continue;
}

logDebug(`Removing .ts extensions from ${entry.path}.`);
removeTsExtensions(entry.path);
logDebug("Moving to next file.");
logDebug("");
}

console.log(msg);
logDebug("Done removing .ts extensions from source files.");
}

try {
/**
* Create the workspace directory.
*/
function createWorkspace() {
logDebug(`Creating ${workspace}.`);
emptyDirSync("./node_modules");
emptyDirSync(workspace);
ensureDirSync(workspace);
logDebug(`Copying Rhum source files to ${workspace}.`);
copySync("./src", workspace + "/src", { overwrite: true });
copySync("./mod.ts", workspace + "/mod.ts", { overwrite: true });
} catch (error) {
logDebug(error);
Deno.exit(1);
}

logDebug("Starting .ts extension removal process.");

for await (const entry of walk(workspace)) {
if (!entry.isFile) {
continue;
for (const item of args) {
const nonDotFilename = item.replace("./", "/");
logDebug(`Copying ${item} to ${workspace}${nonDotFilename}.`);
copySync(item, workspace + nonDotFilename, { overwrite: true });
}

logDebug(`Removing .ts extensions from ${entry.path}.`);
removeTsExtensions(entry.path);
logDebug("Moving to next file.\n\n");
}

logDebug("Done removing .ts extensions from source files.");

/**
* Remove the .ts extensions for runtimes that do not require it.
*/
Expand Down Expand Up @@ -83,11 +128,58 @@ function removeTsExtensions(filename: string): void {
});
}

logDebug(`New contents (without .ts extensions):`);
logDebug(contents);
if (debugContents) {
logDebug(`New contents (without .ts extensions):`);
logDebug(contents);
}

// Step 5: Rewrite the original file without .ts extensions
logDebug(`Overwriting ${filename} with new contents.`);
Deno.writeFileSync(filename, encoder.encode(contents));
logDebug("File written.");
}

/**
* Log output.
* @param msg The message to log.
*/
function logDebug(...msg: unknown[]): void {
if (!debug) {
return;
}

console.log(...msg);
}

/**
* Is the given option enabled?
* @param option The name of the option (e.g., `--debug`).
* @returns True if yes, false if no.
*/
function optionEnabled(option: string): boolean {
const optionIndex = args.indexOf(option);
const enabled = optionIndex !== -1;

if (enabled) {
args.splice(optionIndex, 1);
}

return enabled;
}

/**
* What is the given option value?
* @param option The name of the option (e.g., `--workspace`).
* @returns The value of the option if the option exists.
*/
function optionValue(option: string): boolean {
const extractedOption = args.filter((arg) => arg.includes(option));

if (!extractedOption.length) {
return;
}

args.splice(args.indexOf(extractedOption[0], 1));

return extractedOption[0].replace(option + "=", "");
}
4 changes: 2 additions & 2 deletions console/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export {
emptyDirSync,
ensureDirSync,
walk,
} from "https://deno.land/std@0.141.0/fs/mod.ts";
export { copySync } from "https://deno.land/std@0.141.0/fs/copy.ts";
} from "https://deno.land/std@0.167.0/fs/mod.ts";
export { copySync } from "https://deno.land/std@0.167.0/fs/copy.ts";
2 changes: 1 addition & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export function Stub<OriginalObject, ReturnValue>(
// the value of `returnValue`.
if (typeof obj === "object" && dataMember !== undefined) {
// If we are stubbing a method, then make sure the method is still callable
if (typeof obj[dataMember] === "function") {
if (typeof obj![dataMember] === "function") {
Object.defineProperty(obj, dataMember, {
value: () => returnValue !== undefined ? returnValue : "stubbed",
writable: true,
Expand Down
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,29 @@
"author": "Drash Land",
"license": "MIT",
"scripts": {
"build": "console/build_esm_lib && yarn build:cjs && yarn build:esm",
"build": "yarn build:esm-lib && yarn && yarn build:esm && yarn build:cjs",
"build:cjs": "tsc --project tsconfig.cjs.json",
"build:conversion-workspace": "deno run --allow-read --allow-write ./console/build_esm_lib.ts",
"build:esm": "tsc --project tsconfig.esm.json",
"build:windows": "bash console/build_esm_lib && yarn build:cjs && yarn build:esm",
"check": "rm -rf node_modules/ && rm yarn.lock && yarn install && yarn build && yarn test",
"build:esm-lib": "console/build_esm_lib ./src ./mod.ts --workspace=./tmp/conversion_workspace --debug",
"build:windows": "bash console/build_esm_lib ./src ./mod.ts --workspace=./tmp/conversion_workspace --debug && yarn && yarn build:cjs && yarn build:esm",
"release": "yarn publish --access public",
"test": "jest"
"test": "yarn test:deno && yarn test:cjs && yarn test:esm",
"test:cjs": "yarn jest tests/cjs/",
"test:deno": "deno test -A tests/deno/",
"test:esm": "yarn jest tests/esm/",
"validate:nix": "rm -rf node_modules && rm yarn.lock && yarn build && yarn test"
},
"devDependencies": {
"@babel/core": "7.x",
"@babel/preset-env": "7.x",
"@types/jest": "27.x",
"@types/node": "16.x",
"babel-jest": "27.x",
"jest": "27.x",
"ts-jest": "27.x",
"ts-node": "10.x",
"tsc": "2.x",
"typescript": "4.x"
},
"files": [
Expand Down
11 changes: 4 additions & 7 deletions src/fake/fake_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,11 @@ export class FakeBuilder<ClassToFake> extends TestDoubleBuilder<ClassToFake> {
...params: unknown[]
) => unknown);

// We need to check if the method was pre-preprogrammed to return
// something. If it was, then we make sure that this method we are
// currently defining returns that pre-programmed value.
// We need to check if the method was pre-preprogrammed to do something.
// If it was, then we make sure that this method we are currently
// defining returns that pre-programmed expectation.
if (methodToCall instanceof PreProgrammedMethod) {
if (methodToCall.will_throw) {
throw methodToCall.error;
}
return methodToCall.return;
return methodToCall.run(args);
}

// When method calls its original self, let the `this` context of the
Expand Down
26 changes: 23 additions & 3 deletions src/fake/fake_mixin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IFake } from "../interfaces.ts";
import type { IFake, IMethodChanger } from "../interfaces.ts";
import type { Constructor, MethodOf } from "../types.ts";
import { FakeError } from "../errors.ts";

Expand Down Expand Up @@ -30,6 +30,14 @@ export function createFake<OriginalConstructor, OriginalObject>(
*/
#original!: OriginalObject;

/**
* Map of pre-programmed methods defined by the user.
*/
#pre_programmed_methods: Map<
MethodOf<OriginalObject>,
IMethodChanger<unknown>
> = new Map();

////////////////////////////////////////////////////////////////////////////
// FILE MARKER - CONSTRUCTOR ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -57,7 +65,13 @@ export function createFake<OriginalConstructor, OriginalObject>(
*/
public method<ReturnValueType>(
methodName: MethodOf<OriginalObject>,
): PreProgrammedMethod<OriginalObject, ReturnValueType> {
): IMethodChanger<ReturnValueType> {
// If the method was already pre-programmed previously, then return it so
// the user can add more method setups to it
if (this.#pre_programmed_methods.has(methodName)) {
return this.#pre_programmed_methods.get(methodName)!;
}

const methodConfiguration = new PreProgrammedMethod<
OriginalObject,
ReturnValueType
Expand All @@ -80,7 +94,13 @@ export function createFake<OriginalConstructor, OriginalObject>(
writable: true,
});

return methodConfiguration;
const methodChanger = methodConfiguration as unknown as IMethodChanger<
ReturnValueType
>;

this.#pre_programmed_methods.set(methodName, methodChanger);

return methodChanger;
}
}();
}
Loading

0 comments on commit 73ec134

Please sign in to comment.