Last active
January 1, 2023 19:34
-
-
Save marcocesarato/78fbd26f224f36fa8804fd9d6c069ba0 to your computer and use it in GitHub Desktop.
Fizz Buzz quiz with clean code and TDD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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(); |
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
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.