testCyclesAreWarnedAbout

tcmts.cli.test.e2e.cycles.testCyclesAreWarnedAbout · #iqir55tx · term

Saving says when it makes a cycle worth avoiding: one only types make (an interface breaks it), or a big one of code calling itself; two functions recursing together, and a cycle saved again as it was, aren't mentioned

import { okIn, tempDir } from "#codebase/tcmts/cli/test/e2e/harness";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

export const testCyclesAreWarnedAbout = () => {
  const dir = tempDir("cycle warnings");
  const tcm = (...args: string[]) => okIn(dir, ...args);
  tcm("init");
  const save = (code: string, mode = "add") => {
    fs.writeFileSync(path.join(dir, "scratch.ts"), `// tcm: namespace lib\n${code}`);
    return tcm(mode);
  };
  const pair = save(
    `export const isEven = (n: number): boolean => (n === 0 ? true : isOdd(n - 1));\nexport const isOdd = (n: number): boolean => (n === 0 ? false : isEven(n - 1));\n`,
  );
  assert.doesNotMatch(pair, /warning: .*cycle/, "two functions recursing together are fine");

  const typed = save(
    `export class Shop {\n  name = "corner";\n  describe(): string { return describeShop(this); }\n}\nexport const describeShop = (s: Shop): string => "the " + s.name + " shop";\n`,
  );
  assert.match(typed, /warning: lib\.Shop, lib\.describeShop became one cycle \(2 definitions\)/);
  assert.match(
    typed,
    /only because types name each other \(lib\.describeShop's types name lib\.Shop\)/,
  );

  const big = save(
    `export const a = (n: number): number => (n > 0 ? b(n - 1) : 0);\nexport const b = (n: number): number => (n > 0 ? c(n - 1) : 1);\nexport const c = (n: number): number => (n > 0 ? d(n - 1) : 2);\nexport const d = (n: number): number => (n > 0 ? e(n - 1) : 3);\nexport const e = (n: number): number => (n > 0 ? a(n - 1) : 4);\n`,
  );
  assert.match(big, /became one cycle \(5 definitions\)[^\n]*They call each other/);

  // saved again as it is (a comment changed): nothing new to say
  const again = save(
    `export const a = (n: number): number => (n > 0 ? b(n - 1) : 0); // the first\n`,
    "update",
  );
  assert.doesNotMatch(again, /warning: .*cycle/);
}

uses