Skip to content

Instantly share code, notes, and snippets.

@marcocesarato
Last active January 1, 2023 19:34
Show Gist options
  • Save marcocesarato/78fbd26f224f36fa8804fd9d6c069ba0 to your computer and use it in GitHub Desktop.
Save marcocesarato/78fbd26f224f36fa8804fd9d6c069ba0 to your computer and use it in GitHub Desktop.
Fizz Buzz quiz with clean code and TDD
/**
* Runner
*/
main();
/**
* Program with Clean Code
*/
function main() {
const result = program({ 3: "Fizz", 5: "Buzz", 7: "Bang" }, 100);
result.forEach((element) => {
console.log(element);
});
}
function program(obj, num) {
let result = [];
for (let i = 1; i <= num; i++) {
let element = "";
Object.keys(obj).forEach((key) => {
if (i % key === 0) {
element += obj[key];
}
});
result.push(element || i);
}
return result;
}
/**
* Test Driven Development
*/
global.testProgram = () => {
const result = program(
{ 3: "Fizz", 5: "Buzz", 7: "Bang" },
lcm(3, 5, 7) + 10
);
result.unshift(null); // Increment the array index for convenience
// Least common multiples
assert(
result[lcm(3, 5, 7)],
"FizzBuzzBang",
`lcm(3, 5, 7) give FizzBuzzBang`
);
assert(result[lcm(5, 7)], "BuzzBang", `lcm(5, 7) give BuzzBang`);
assert(result[lcm(3, 7)], "FizzBang", `lcm(3, 7) give FizzBang`);
assert(result[lcm(3, 5)], "FizzBuzz", `lcm(3,5) give FizzBuzz`);
// Plain numbers
assert(result[7], "Bang", "7 give Bang");
assert(result[5], "Buzz", "5 give Buzz");
assert(result[3], "Fizz", "3 give Fizz");
assert(result[4], 4, "4 give 4");
assert(result[2], 2, "2 give 2");
};
/**
* Utils
*/
function test() {
const testFunctions = {};
const globalObject = typeof window === "undefined" ? global : window;
Object.keys(globalObject).forEach((key) => {
if (
key.startsWith("test") &&
key !== "test" &&
typeof globalObject[key] === "function"
) {
testFunctions[key] = globalObject[key];
}
});
console.log("\n---");
console.log("Testing");
console.log("---");
this.totalsExecuted = 0;
this.totalsPassed = 0;
this.suitesExecuted = 0;
this.suitesPassed = 0;
Object.keys(testFunctions).forEach((name) => {
const testFunc = testFunctions[name];
this.executed = 0;
this.passed = 0;
console.log(`• ${name.replace("test", "")}`);
try {
testFunc();
} catch (e) {
console.log("ERROR");
console.error(e);
}
this.totalsExecuted += this.executed;
this.totalsPassed += this.passed;
this.suitesExecuted++;
if (this.executed === this.passed) {
this.suitesPassed++;
}
console.log(` Tests: ${passed} passed, ${executed} total`);
});
console.log("---");
console.log(`Tests: ${totalsPassed} passed, ${totalsExecuted} total`);
console.log(`Test Suites: ${suitesPassed} passed, ${suitesExecuted} total`);
console.log("---");
}
function assert(result, expectedOutput, expectedMessage) {
this.executed++;
if (result !== expectedOutput) {
console.error(` ✘ Assert ${expectedMessage}`);
return false;
}
this.passed++;
console.log(` √ Assert ${expectedMessage}`);
return true;
}
function lcm(...numbers) {
if (numbers.length === 0) return;
let result = numbers[0];
for (let i = 1; i < numbers.length; i++) {
result = (result * numbers[i]) / gcd(result, numbers[i]);
}
return result;
}
function gcd(a, b) {
if (b === 0) return a;
return gcd(b, a % b);
}
/**
* Test Runner
*/
test();
@marcocesarato
Copy link
Author

marcocesarato commented Jul 25, 2022

Write a program, using clean code principles and TDD (Test Driven Development), that prints the numbers from 1 to 100. But for multiples of 3 print “Fizz” instead of the number and for the multiples of 5 print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz “. Make it also extendible adding 7 that print Bang.

@marcocesarato
Copy link
Author

marcocesarato commented Jul 26, 2022

Code wthout a solution:

/**
 * Runner
 */

main();

/**
 * Program with Clean Code
 */

function main() {
  // your code ...
}

/**
 * Test Driven Development
 */

global.testProgram = () => {
  // add your test assert using `assert(true, true, "description")`
}

/**
 * Utils
 */

function test() {
  const testFunctions = {};
  const globalObject = typeof window === "undefined" ? global : window;
  Object.keys(globalObject).forEach((key) => {
    if (
      key.startsWith("test") &&
      key !== "test" &&
      typeof globalObject[key] === "function"
    ) {
      testFunctions[key] = globalObject[key];
    }
  });

  console.log("\n---");
  console.log("Testing");
  console.log("---");

  this.totalsExecuted = 0;
  this.totalsPassed = 0;
  this.suitesExecuted = 0;
  this.suitesPassed = 0;

  Object.keys(testFunctions).forEach((name) => {
    const testFunc = testFunctions[name];
    this.executed = 0;
    this.passed = 0;

    console.log(`• ${name.replace("test", "")}`);

    try {
      testFunc();
    } catch (e) {
      console.log("ERROR");
      console.error(e);
    }

    this.totalsExecuted += this.executed;
    this.totalsPassed += this.passed;
    this.suitesExecuted++;
    if (this.executed === this.passed) {
      this.suitesPassed++;
    }

    console.log(`  Tests: ${passed} passed, ${executed} total`);
  });
  console.log("---");
  console.log(`Tests: ${totalsPassed} passed, ${totalsExecuted} total`);
  console.log(`Test Suites: ${suitesPassed} passed, ${suitesExecuted} total`);
  console.log("---");
}

function assert(result, expectedOutput, expectedMessage) {
  this.executed++;
  if (result !== expectedOutput) {
    console.error(`    ✘  Assert ${expectedMessage}`);
    return false;
  }
  this.passed++;
  console.log(`    √  Assert ${expectedMessage}`);
  return true;
}

function lcm(...numbers) {
  if (numbers.length === 0) return;

  let result = numbers[0];
  for (let i = 1; i < numbers.length; i++) {
    result = (result * numbers[i]) / gcd(result, numbers[i]);
  }
  return result;
}

function gcd(a, b) {
  if (b === 0) return a;
  return gcd(b, a % b);
}

/**
 * Test Runner
 */

test();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment