diff --git a/src/testing.md b/src/testing.md index 25586f2..b2c5a3a 100644 --- a/src/testing.md +++ b/src/testing.md @@ -2,77 +2,98 @@ ## 6.1 유닛 테스트(Unit test) -유닛 테스트로 69.6%의 Line Coverage와 73.4%의 Function Coverage를 달성했다. -다음과 같은 로그가 있다. +유닛 테스트로 63.7%의 Line Coverage와 67.5%의 Function Coverage를 달성했다. +### permission.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|permission.test|✅|14ms| +|permission empty|✅|16ms| +### session.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|Session : set |✅|14ms| +|Session : delete |✅|16ms| +|Login Handler : login with invalid format |✅|15ms| +|Login Handler : login with invalid password |✅|16ms| +|Login Handler : login |✅|15ms| +|Login Handler : logout with no session |✅|17ms| +|Login Handler : logout |✅|16ms| +|getSession|✅|15ms| +|getSession with invalid cookie|✅|15ms| +### user.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|user.createAdminUser|✅|5ms| +### filedoc.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|readDocFile|✅|12ms| +|readDocFile: not found|✅|15ms| +|readDocFile: invalid json|✅|15ms| +|saveDocFile|✅|15ms| +### methodHandle.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|methodHandle: basic methods|✅|14ms| +|methodHandle: not found|✅|15ms| +|methodHandle: options|✅|17ms| +### route.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|route: basic route|✅|6ms| +|route: double slash route|✅|12ms| +|route: double match|✅|16ms| +|route: test context|✅|15ms| +|route: test regex|✅|15ms| +|route: test not found|✅|2ms| +|route: encode_route|✅|12ms| +|route: router in router|✅|15ms| +### chunk.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|basic chunk operation : create chunk |✅|13ms| +|basic chunk operation : delete chunk |✅|15ms| +|basic chunk operation : modify chunk |✅|16ms| +|basic chunk operation : move chunk |✅|16ms| +|basic chunk operation : invalid chunk operation |✅|16ms| +|test chunk notification operation|✅|16ms| +|test chunk conflict|✅|15ms| +|test chunk conflict resolve with history|✅|32ms| +### doc.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|handleDocumentMethod|✅|5ms| +|handleTagMethod : setTag |✅|9ms| +|handleTagMethod : getTag |✅|16ms| +|handleTagMethod : conflict |✅|16ms| +### share.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|handleShareGetInfo|✅|16ms| +|handleShareDocMethod|✅|2ms| +|handleShareMethod with no existing share token|✅|12ms| +### server.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|server rpc test|✅|4s| +### fswatcher.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|WatchFilteredReadWriter|✅|79ms| +### readWriter.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|QueueReadWriter|✅|57ms| +### util.test.ts +| name | result | duration | +| ---- | ------ | -------- | +|watcher util isHidden|✅|5ms| -``` -running 2 tests from ./src/auth/permission.test.ts -permission.test ... ok (8ms) -permission empty ... ok (16ms) -running 4 tests from ./src/auth/session.test.ts -Session ... - set ... ok (9ms) - delete ... ok (16ms) -ok (42ms) -Login Handler ... - login with invalid format ... ok (15ms) - login with invalid password ... ok (16ms) - login ... ok (16ms) - logout with no session ... ok (16ms) - logout ... ok (16ms) -ok (96ms) -getSession ... ok (16ms) -getSession with invalid cookie ... ok (16ms) -running 1 test from ./src/auth/user.test.ts -user.createAdminUser ... ok (15ms) -running 4 tests from ./src/document/filedoc.test.ts -readDocFile ... ok (19ms) -readDocFile: not found ... ok (16ms) -readDocFile: invalid json ... ok (16ms) -saveDocFile ... ok (15ms) -running 3 tests from ./src/router/methodHandle.test.ts -methodHandle: basic methods ... ok (8ms) -methodHandle: not found ... ok (16ms) -methodHandle: options ... ok (16ms) -running 8 tests from ./src/router/route.test.ts -route: basic route ... ok (10ms) -route: double slash route ... ok (16ms) -route: double match ... ok (16ms) -route: test context ... ok (16ms) -route: test regex ... ok (16ms) -route: test not found ... ok (16ms) -route: encode_route ... ok (2ms) -route: router in router ... ok (13ms) -running 4 tests from ./src/rpc/chunk.test.ts -basic chunk operation ... - create chunk ... ok (19ms) - delete chunk ... ok (15ms) - modify chunk ... ok (15ms) - move chunk ... ok (15ms) - invalid chunk operation ... ok (17ms) -ok (98ms) -test chunk notification operation ... ok (15ms) -test chunk conflict ... ok (16ms) -test chunk conflict resolve with history ... ok (32ms) -running 2 tests from ./src/rpc/doc.test.ts -handleDocumentMethod ... ok (4ms) -handleTagMethod ... - setTag ... ok (13ms) - getTag ... ok (15ms) - conflict ... ok (15ms) -ok (61ms) -running 3 tests from ./src/rpc/share.test.ts -handleShareGetInfo ... ok (18ms) -handleShareDocMethod ... ok (15ms) -handleShareMethod with no existing share token ... ok (16ms) -running 1 test from ./src/server.test.ts -server rpc test ... ok (1s) -running 3 tests from ./src/setting.test.ts -setting: basic ... ok (35ms) -setting: default value ... ok (7ms) -setting: defered register ... ok (16ms) -test result: ok. 35 passed (15 steps); 0 failed; 0 ignored; 0 measured; 0 filtered out (2s) -``` +### Total + +| name | passed | Steps | Failed | duration | +| ---- | ------ | ----- | ------ | -------- | +| ok | 35 | 15 | 0 | 4726ms | ## 6.2 기능 테스트(Functional Test) diff --git a/tools/unittestToDoc.ts b/tools/unittestToDoc.ts new file mode 100644 index 0000000..40696a7 --- /dev/null +++ b/tools/unittestToDoc.ts @@ -0,0 +1,206 @@ +const test_stdout: string = `running 2 tests from ./src/auth/permission.test.ts +permission.test ... ok (14ms) +permission empty ... ok (16ms) +running 4 tests from ./src/auth/session.test.ts +Session ... + set ... ok (14ms) + delete ... ok (16ms) +ok (49ms) +Login Handler ... + login with invalid format ... ok (15ms) + login with invalid password ... ok (16ms) + login ... ok (15ms) + logout with no session ... ok (17ms) + logout ... ok (16ms) +ok (94ms) +getSession ... ok (15ms) +getSession with invalid cookie ... ok (15ms) +running 1 test from ./src/auth/user.test.ts +user.createAdminUser ... ok (5ms) +running 4 tests from ./src/document/filedoc.test.ts +readDocFile ... ok (12ms) +readDocFile: not found ... ok (15ms) +readDocFile: invalid json ... ok (15ms) +saveDocFile ... ok (15ms) +running 3 tests from ./src/router/methodHandle.test.ts +methodHandle: basic methods ... ok (14ms) +methodHandle: not found ... ok (15ms) +methodHandle: options ... ok (17ms) +running 8 tests from ./src/router/route.test.ts +route: basic route ... ok (6ms) +route: double slash route ... ok (12ms) +route: double match ... ok (16ms) +route: test context ... ok (15ms) +route: test regex ... ok (15ms) +route: test not found ... ok (2ms) +route: encode_route ... ok (12ms) +route: router in router ... ok (15ms) +running 4 tests from ./src/rpc/chunk.test.ts +basic chunk operation ... + create chunk ... ok (13ms) + delete chunk ... ok (15ms) + modify chunk ... ok (16ms) + move chunk ... ok (16ms) + invalid chunk operation ... ok (16ms) +ok (96ms) +test chunk notification operation ... ok (16ms) +test chunk conflict ... ok (15ms) +test chunk conflict resolve with history ... ok (32ms) +running 2 tests from ./src/rpc/doc.test.ts +handleDocumentMethod ... ok (5ms) +handleTagMethod ... + setTag ... ok (9ms) + getTag ... ok (16ms) + conflict ... ok (16ms) +ok (58ms) +running 3 tests from ./src/rpc/share.test.ts +handleShareGetInfo ... ok (16ms) +handleShareDocMethod ... ok (2ms) +handleShareMethod with no existing share token ... ok (12ms) +running 1 test from ./src/server.test.ts +server rpc test ... ok (4s) +running 1 test from ./src/watcher/fswatcher.test.ts +WatchFilteredReadWriter ... ok (79ms) +running 1 test from ./src/watcher/readWriter.test.ts +QueueReadWriter ... ok (57ms) +running 1 test from ./src/watcher/util.test.ts +watcher util isHidden ... ok (5ms) + +test result: ok. 35 passed (15 steps); 0 failed; 0 ignored; 0 measured; 0 filtered out (6s) +`; + +interface TestStep{ + name: string; + result: boolean; + time: number; +} + +interface TestResult{ + name: string; + result: boolean; + time: number; + steps: TestStep[]; +} + +interface TestFiles{ + path: string; + tests: TestResult[]; +} + +const lines = test_stdout.split("\n"); +let cur = 0; + +function getMs(time: string){ + if (time.endsWith("ms")){ + return parseInt(time.replace("ms", "")); + } + return parseInt(time.replace("s", "")) * 1000; +} + +let testFiles: TestFiles[] = []; + +function parseTest(): TestResult { + const m = /^(.*) \.\.\.(.*)/.exec(lines[cur]); + let steps: TestStep[] = [] + if(m){ + const name = m[1]; + const status = m[2]; + let result = status.includes("ok"); + let time = 0; + if(status === ""){ + cur++; + while(!lines[cur].startsWith("ok")){ + const s = /^ (.*) \.\.\. (.*) \((\d+m?s)\)/.exec(lines[cur]); + if(!s){ + console.log("unexpected line: " + lines[cur]); + Deno.exit(1); + } + const stepname = s[1]; + const stepstatus = s[2]; + const steptime = s[3]; + //console.log(`${name} ${stepname} ${stepstatus} ${steptime}`); + steps.push({name: stepname, result: stepstatus.includes("ok"), time: getMs(steptime)}); + cur++; + } + result = lines[cur].startsWith("ok"); + time = getMs(lines[cur].match(/\d+m?s/)![0]); + } + else{ + time = getMs(status.match(/\d+m?s/)![0]); + } + //console.log(name, result, time); + cur++; + return {name, result, time, steps}; + } + console.log("unexpected line: " + lines[cur]); + Deno.exit(1); +} + +while(cur < lines.length){ + const line = lines[cur]; + if(line === ""){ + cur++; + break; + } + const m = /^running (\d+) tests? from (.+)/.exec(lines[cur]); + if(m){ + const num = parseInt(m[1]); + const file = m[2]; + //console.log(`${num} tests from ${file}`); + cur++; + let tests = []; + for(let i = 0; i < num; i++){ + const test = parseTest(); + tests.push(test); + } + testFiles.push({path: file, tests}); + } + else { + console.log("%c unexpected : "+line,"color: red"); + break; + } + //console.log("endwith " + cur); +} + +const lastResultRegex = /test result: (.*)\. (\d+) passed \((\d+) steps\); (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out \((\d+m?s)\)/; +const mm = lastResultRegex.exec(lines[cur]); +if(!mm){ + console.log("unexpected line: " + lines[cur]); + Deno.exit(1); +} +const mok = mm[1]; +const numPassed = parseInt(mm[2]); +const numSteps = parseInt(mm[3]); +const numFailed = parseInt(mm[4]); +const numIgnored = parseInt(mm[5]); +const numMeasured = parseInt(mm[6]); +const numFiltered = parseInt(mm[7]); +const time = getMs(mm[8]); + + +import * as path from "https://deno.land/std@0.142.0/path/mod.ts"; + +let duration = 0; +//console.log(testFiles); +testFiles.forEach(file => { + console.log(`### ${path.basename(file.path)}`); + console.log(`| name | result | duration |`); + console.log(`| ---- | ------ | -------- |`); + file.tests.forEach(test => { + if(test.steps.length > 0){ + test.steps.forEach(step => { + console.log(`|${test.name + " : " + step.name} |${step.result ? "✅" : "❌"}|${step.time}ms|`); + duration += step.time; + }); + } + else{ + console.log(`|${test.name}|${test.result ? "✅" : "❌"}|${test.time}ms|`); + duration += test.time; + } + }); +}); + +console.log(`### Total`); +console.log(`| name | passed | Steps | Failed | duration |`); +console.log(`| ---- | ------ | ----- | ------ | -------- |`); +console.log(`| ${mok} | ${numPassed} | ${numSteps} | ${numFailed} | ${duration}ms |`); \ No newline at end of file