diff --git a/surveys/code_coverage/.gitignore b/surveys/code_coverage/.gitignore new file mode 100644 index 0000000..404abb2 --- /dev/null +++ b/surveys/code_coverage/.gitignore @@ -0,0 +1 @@ +coverage/ diff --git a/surveys/code_coverage/README.md b/surveys/code_coverage/README.md new file mode 100644 index 0000000..12edb8d --- /dev/null +++ b/surveys/code_coverage/README.md @@ -0,0 +1,20 @@ +# Code coverage survery + +## Test + +``` +deno task test-coverage +``` + +## Instructions + +Write 1) a test inside `program_1_test.ts`, testing `playerFromUnknown` and 2) a test inside `program_2_test.ts`, testing `stringToInt`. The goal should be to __test as much as the code as possible__, meaning every branch and every line of code should be tested. + +The tests are done, when the participant is satisfied (or the time is up). Afterward, generate a coverage report using the following command. + +```sh +deno task test-coverage +``` + +Note down the branch and line coverage percentages of each file. + diff --git a/surveys/code_coverage/deno.jsonc b/surveys/code_coverage/deno.jsonc new file mode 100644 index 0000000..7aac543 --- /dev/null +++ b/surveys/code_coverage/deno.jsonc @@ -0,0 +1,8 @@ +{ + "fmt": { + "indentWidth": 4 + }, + "tasks": { + "test-coverage": "deno test --coverage && deno coverage coverage/ && deno coverage coverage/ --html && firefox --file coverage/html/index.html" + } +} diff --git a/surveys/code_coverage/deno.lock b/surveys/code_coverage/deno.lock new file mode 100644 index 0000000..b742530 --- /dev/null +++ b/surveys/code_coverage/deno.lock @@ -0,0 +1,18 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/assert@*": "1.0.8", + "jsr:@std/internal@^1.0.5": "1.0.5" + }, + "jsr": { + "@std/assert@1.0.8": { + "integrity": "ebe0bd7eb488ee39686f77003992f389a06c3da1bbd8022184804852b2fa641b", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/internal@1.0.5": { + "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba" + } + } +} diff --git a/surveys/code_coverage/program_1.ts b/surveys/code_coverage/program_1.ts new file mode 100644 index 0000000..97d21ae --- /dev/null +++ b/surveys/code_coverage/program_1.ts @@ -0,0 +1,50 @@ +export type Player = { + username: string; + level: number; +}; + +export type Result = { ok: true; value: T } | { ok: false; error: string }; + +export function playerFromUnknown(input: unknown): Result { + if (input === undefined) { + return { ok: false, error: "no input" }; + } + if (input === null) { + return { ok: false, error: "no input" }; + } + if (typeof input === "string") { + if (!/^[\d\w(:?\\\-)]+\-\d+$/.test(input)) { + return { ok: false, error: "malformed player" }; + } + const splits = input.split("-"); + let username = splits[0]; + if (username.includes("\\-")) { + username = username.replaceAll("\\-", "-"); + } + if (splits[1].startsWith("0") && splits[1].length >= 2) { + return { ok: false, error: "malformed player" }; + } + const level = parseInt(splits[1]); + return { ok: true, value: { username, level } }; + } else if (typeof input === "object") { + if (Object.keys(input).length < 2) { + return { ok: false, error: "malformed player" }; + } + if (Object.keys(input).length > 2) { + return { ok: false, error: "too much information" }; + } + if (!("username" in input && "level" in input)) { + return { ok: false, error: "malformed player" }; + } + if (typeof input.username !== "string") { + return { ok: false, error: "malformed player" }; + } + if (typeof input.level !== "number") { + return { ok: false, error: "malformed player" }; + } + const { username, level } = input; + return { ok: true, value: { username, level } }; + } else { + return { ok: false, error: "malformed player" }; + } +} diff --git a/surveys/code_coverage/program_1_test.ts b/surveys/code_coverage/program_1_test.ts new file mode 100644 index 0000000..a15bc89 --- /dev/null +++ b/surveys/code_coverage/program_1_test.ts @@ -0,0 +1,13 @@ +import { assertEquals } from "jsr:@std/assert"; +import { playerFromUnknown } from "./program_1.ts"; + +Deno.test("must work", () => { + assertEquals( + playerFromUnknown("miklz-33"), + { ok: true, value: { username: "miklz", level: 33 } }, + ); + assertEquals( + playerFromUnknown({ username: "piet", level: 2 }), + { ok: true, value: { username: "piet", level: 2 } }, + ); +}); diff --git a/surveys/code_coverage/program_2.ts b/surveys/code_coverage/program_2.ts new file mode 100644 index 0000000..65c7edd --- /dev/null +++ b/surveys/code_coverage/program_2.ts @@ -0,0 +1,45 @@ +// deno-fmt-ignore +const charVal: {[key: string]: number} = { + "0": 0, "1": 1, "2": 2, "3": 3, + "4": 4, "5": 5, "6": 6, "7": 7, + "8": 8, "9": 9, "a": 10, "b": 11, + "c": 12, "d": 13, "e": 14, "f": 15, +}; +const base2Digits = ["0", "1"]; +const base8Digits = [...base2Digits, "2", "3", "4", "5", "6", "7"]; +const base10Digits = [...base8Digits, "8", "9"]; +const base16Digits = [...base10Digits, "a", "b", "c", "d", "e", "f"]; + +export function stringToInt(text: string): number { + if (text.length === 0) { + return NaN; + } + if (text[0] === "0") { + if (text.length === 1) { + return 0; + } else if (text[1] == "b") { + return parseDigits(text.slice(2), 2, base2Digits); + } else if (text[1] == "x") { + return parseDigits(text.slice(2), 16, base16Digits); + } else { + return parseDigits(text.slice(1), 8, base8Digits); + } + } + return parseDigits(text, 10, base10Digits); +} + +function parseDigits( + numberText: string, + base: number, + digitSet: string[], +): number { + let value = 0; + for (const ch of numberText) { + value *= base; + if (!digitSet.includes(ch)) { + return NaN; + } + value += charVal[ch]; + } + return value; +} diff --git a/surveys/code_coverage/program_2_test.ts b/surveys/code_coverage/program_2_test.ts new file mode 100644 index 0000000..e0425e2 --- /dev/null +++ b/surveys/code_coverage/program_2_test.ts @@ -0,0 +1,11 @@ +import { assertEquals } from "jsr:@std/assert"; +import { stringToInt } from "./program_2.ts"; + +Deno.test("must work", () => { + assertEquals(stringToInt("0"), 0); + assertEquals(stringToInt("10"), 10); + assertEquals(stringToInt("0b110"), 6); + assertEquals(stringToInt("071"), 57); + assertEquals(stringToInt("0xaa"), 170); + assertEquals(stringToInt("john"), NaN); +}); diff --git a/surveys/code_coverage/survey.ods b/surveys/code_coverage/survey.ods new file mode 100644 index 0000000..e5da3de Binary files /dev/null and b/surveys/code_coverage/survey.ods differ diff --git a/surveys/flame_graph/README.md b/surveys/flame_graph/README.md new file mode 100644 index 0000000..c3243b2 --- /dev/null +++ b/surveys/flame_graph/README.md @@ -0,0 +1,38 @@ + +# Flame graph survey + +Look at the following code. + +```rs +fn add(a, b) { + + a b +} + +let result = 0; +let i = 0; +loop { + if >= i 10 { + break; + } + result = add(result, 5); + i = + i 1; +} +``` + +Imagine you were to run the code. +``` +slige --run program.slg +``` + +What percantage distribution of the total execution time is spent in `main` and in `add`? Remember that all time spent in `add` is also time spent in `main`. + +Examples: + +Total program | Inside `main` | Inside `add` +---|---|--- +100% | 80% | 40% +100% | 90% | 10% +100% | 96% | 70% + +Note down the guesses. + diff --git a/surveys/flame_graph/program_flame_graph.png b/surveys/flame_graph/program_flame_graph.png new file mode 100644 index 0000000..78ee82c Binary files /dev/null and b/surveys/flame_graph/program_flame_graph.png differ diff --git a/surveys/flame_graph/survey.ods b/surveys/flame_graph/survey.ods new file mode 100644 index 0000000..72153e3 Binary files /dev/null and b/surveys/flame_graph/survey.ods differ diff --git a/web/example.slg b/web/example.slg new file mode 100644 index 0000000..927726f --- /dev/null +++ b/web/example.slg @@ -0,0 +1,14 @@ +fn add(a, b) { + + a b +} + +let result = 0; +let i = 0; +loop { + if >= i 10 { + break; + } + result = add(result, 5); + i = + i 1; +} +