





















@@ -505,29 +505,6 @@ describe("scanDirectoryWithSummary", () => {
505505}
506506});
507507508-it("includes warn-severity findings in summary counts (lines 568-569)", async () => {
509-const root = makeTmpDir();
510-writeFixtureFiles(root, {
511-// obfuscated-code rule produces 'warn' severity
512-"a.js": `const payload = "\\x72\\x65\\x71\\x75\\x69\\x72\\x65";`,
513-});
514-const summary = await scanDirectoryWithSummary(root);
515-expect(summary.warn).toBeGreaterThanOrEqual(1);
516-});
517-518-it("skips non-scanned files in scanDirectory (line 535)", async () => {
519-const root = makeTmpDir();
520-writeFixtureFiles(root, {
521-// File bigger than maxFileBytes — scanned=false → hits the continue at line 535
522-"large.js": `eval("${"A".repeat(4096)}");`,
523-// Small clean file to confirm the scan ran
524-"clean.js": `export const ok = true;`,
525-});
526-const findings = await scanDirectory(root, { maxFileBytes: 64 });
527-// large.js is skipped (too big), clean.js has no findings
528-expect(findings).toHaveLength(0);
529-});
530-531508it("throws when reading a scannable file fails", async () => {
532509const root = makeTmpDir();
533510const filePath = path.join(root, "bad.js");
@@ -551,59 +528,7 @@ describe("scanDirectoryWithSummary", () => {
551528}
552529});
553530554-it("returns scanned=false when readFile throws ENOENT after stat (line 506 — TOCTOU)", async () => {
555-const root = makeTmpDir();
556-const filePath = path.join(root, "vanishing.js");
557-fsSync.writeFileSync(filePath, `const x = eval("1+1");`);
558-559-const realReadFile = fs.readFile;
560-const spy = vi.spyOn(fs, "readFile").mockImplementation(async (...args) => {
561-const pathArg = args[0];
562-if (typeof pathArg === "string" && pathArg === filePath) {
563-const err = new Error("ENOENT: no such file or directory") as NodeJS.ErrnoException;
564-err.code = "ENOENT";
565-throw err;
566-}
567-return await realReadFile(...args);
568-});
569-570-try {
571-// File vanishes between stat and readFile — should return empty findings, not throw
572-const findings = await scanDirectory(root);
573-expect(findings).toHaveLength(0);
574-} finally {
575-spy.mockRestore();
576-}
577-});
578-579-it("returns scanned=false when stat returns non-file for a walked path (line 474)", async () => {
580-const root = makeTmpDir();
581-const filePath = path.join(root, "became-a-dir.js");
582-fsSync.writeFileSync(filePath, `const x = eval("1+1");`);
583-584-const realStat = fs.stat;
585-const spy = vi.spyOn(fs, "stat").mockImplementation(async (...args) => {
586-const pathArg = args[0];
587-if (typeof pathArg === "string" && pathArg === filePath) {
588-// Return a stat that looks like a directory after the walk collected it
589-const realSt = await realStat(pathArg);
590-const fake = Object.assign(Object.create(Object.getPrototypeOf(realSt)), realSt);
591-fake.isFile = () => false;
592-fake.isDirectory = () => true;
593-return fake;
594-}
595-return await realStat(...args);
596-});
597-598-try {
599-const findings = await scanDirectory(root);
600-expect(findings).toHaveLength(0);
601-} finally {
602-spy.mockRestore();
603-}
604-});
605-606-it("invalidates file scan cache when maxFileBytes changes between scans (line 94)", async () => {
531+it("invalidates file scan cache when maxFileBytes changes between scans", async () => {
607532// First scan with maxFileBytes=1024: populates cache with entry
608533// Second scan with maxFileBytes=64: size/mtime same but maxFileBytes differs →
609534// getCachedFileScanResult returns undefined (deletes stale entry)
@@ -615,178 +540,15 @@ describe("scanDirectoryWithSummary", () => {
615540expect(findings).toHaveLength(0);
616541});
617542618-it("returns empty entries when dir stat throws ENOENT during walk (line 361)", async () => {
619-// readDirEntriesWithCache: stat(dirPath) throws ENOENT → return [] (line 361)
620-const root = makeTmpDir();
621-writeFixtureFiles(root, { "a.js": `const x = eval("hack");` });
622-623-const realStat = fs.stat;
624-const spy = vi.spyOn(fs, "stat").mockImplementation(async (...args) => {
625-const pathArg = args[0];
626-if (typeof pathArg === "string" && pathArg === root) {
627-const err = new Error("ENOENT: no such file or directory") as NodeJS.ErrnoException;
628-err.code = "ENOENT";
629-throw err;
630-}
631-return await realStat(...args);
632-});
633-634-try {
635-const findings = await scanDirectory(root);
636-expect(findings).toHaveLength(0);
637-} finally {
638-spy.mockRestore();
639-}
640-});
641-642-it("hits dir entry cache on second scan of same directory (line 371)", async () => {
643-const root = makeTmpDir();
644-writeFixtureFiles(root, { "a.js": `export const x = 1;` });
645-// First scan populates the cache
646-await scanDirectory(root);
647-// Second scan within the same test (before afterEach clears cache) hits line 371
648-const findings2 = await scanDirectory(root);
649-expect(findings2).toHaveLength(0);
650-});
651-652-it("breaks collectScannableFiles merge loop when maxFiles reached (line 447)", async () => {
653-// Key: forced file is hidden (not walked), two regular files are walked.
654-// forcedFiles=[.hidden/h.js](1) + walkDir returns [a.js, b.js](2, maxFiles=2)
655-// Merge loop:
656-// iter 1 (a.js): out.length(1) >= 2? false → add → out.length=2
657-// iter 2 (b.js): out.length(2) >= 2? true → BREAK (line 447)
658-const root = makeTmpDir();
659-writeFixtureFiles(root, {
660-".hidden/h.js": `export const h = 1;`, // forced (hidden, not walked)
661-"a.js": `export const x = 1;`, // walked
662-"b.js": `export const y = 2;`, // walked, triggers break
663-});
664-const findings = await scanDirectory(root, {
665-includeFiles: [".hidden/h.js"],
666-maxFiles: 2,
667-});
668-expect(findings).toHaveLength(0);
669-});
670-671-it("returns empty findings when stat throws ENOENT during file scan (line 469)", async () => {
672-// scanFileWithCache: stat throws ENOENT (file deleted between walk and scan)
673-const root = makeTmpDir();
674-const filePath = path.join(root, "ghost.js");
675-fsSync.writeFileSync(filePath, `const x = eval("1+1");`);
676-677-const realStat = fs.stat;
678-const spy = vi.spyOn(fs, "stat").mockImplementation(async (...args) => {
679-const pathArg = args[0];
680-if (typeof pathArg === "string" && pathArg === filePath) {
681-const err = new Error("ENOENT: no such file or directory") as NodeJS.ErrnoException;
682-err.code = "ENOENT";
683-throw err;
684-}
685-return await realStat(...args);
686-});
687-688-try {
689-const findings = await scanDirectory(root);
690-expect(findings).toHaveLength(0);
691-} finally {
692-spy.mockRestore();
693-}
694-});
695-696-it("skips includeFiles entries that escape the root directory (line 404)", async () => {
543+it("skips includeFiles entries that escape the root directory", async () => {
697544const root = makeTmpDir();
698545writeFixtureFiles(root, { "clean.js": `export const x = 1;` });
699546// "../../etc/passwd" resolves outside root — isPathInside returns false → continue
700547const findings = await scanDirectory(root, { includeFiles: ["../../etc/passwd"] });
701548expect(findings).toHaveLength(0);
702549});
703550704-it("returns empty entries when stat returns non-directory for a walked path (line 366)", async () => {
705-// readDirEntriesWithCache: stat succeeds but returns a non-directory
706-const root = makeTmpDir();
707-writeFixtureFiles(root, { "a.js": `const x = eval("1+1");` });
708-709-const realStat = fs.stat;
710-const spy = vi.spyOn(fs, "stat").mockImplementation(async (...args) => {
711-const pathArg = args[0];
712-if (typeof pathArg === "string" && pathArg === root) {
713-// Make the root directory look like a file to readDirEntriesWithCache
714-const realSt = await realStat(pathArg);
715-const fake = Object.assign(Object.create(Object.getPrototypeOf(realSt)), realSt);
716-fake.isDirectory = () => false;
717-fake.isFile = () => true;
718-return fake;
719-}
720-return await realStat(...args);
721-});
722-723-try {
724-const findings = await scanDirectory(root);
725-// Scan returns nothing because readDirEntriesWithCache returns [] for non-dir
726-expect(findings).toHaveLength(0);
727-} finally {
728-spy.mockRestore();
729-}
730-});
731-732-it("re-throws when stat throws non-ENOENT for a directory entry (line 363)", async () => {
733-// readDirEntriesWithCache: stat throws EACCES (not ENOENT) for the root dir
734-const root = makeTmpDir();
735-writeFixtureFiles(root, { "a.js": `export const x = 1;` });
736-737-const realStat = fs.stat;
738-const spy = vi.spyOn(fs, "stat").mockImplementation(async (...args) => {
739-const pathArg = args[0];
740-if (typeof pathArg === "string" && pathArg === root) {
741-const err = new Error("EACCES: permission denied") as NodeJS.ErrnoException;
742-err.code = "EACCES";
743-throw err;
744-}
745-return await realStat(...args);
746-});
747-748-try {
749-await expect(scanDirectory(root)).rejects.toMatchObject({ code: "EACCES" });
750-} finally {
751-spy.mockRestore();
752-}
753-});
754-755-it("skips duplicate entries in includeFiles (line 410 — resolveForcedFiles dedup)", async () => {
756-const root = makeTmpDir();
757-writeFixtureFiles(root, { "a.js": `const x = eval("hack");` });
758-// Pass the same path twice — second occurrence hits seen.has(includePath) → continue
759-const findings = await scanDirectory(root, { includeFiles: ["a.js", "a.js"] });
760-expect(findings.length).toBeGreaterThanOrEqual(1);
761-});
762-763-it("skips forced file when stat returns a directory (line 423)", async () => {
764-const root = makeTmpDir();
765-// Create a DIRECTORY named like a .js file via renaming a dir
766-const dirPath = path.join(root, "notafile.js");
767-fsSync.mkdirSync(dirPath);
768-// includeFiles points at a directory path ending in .js — isScannable passes, stat.isFile() fails
769-const findings = await scanDirectory(root, { includeFiles: ["notafile.js"] });
770-expect(findings).toHaveLength(0);
771-});
772-773-it("re-throws when stat throws a non-ENOENT error for a forced file (line 420)", async () => {
774-const root = makeTmpDir();
775-const filePath = path.join(root, "forbidden.js");
776-fsSync.writeFileSync(filePath, `export const x = 1;`);
777-778-const spy = mockStatPermissionDeniedFor(filePath);
779-780-try {
781-await expect(scanDirectory(root, { includeFiles: ["forbidden.js"] })).rejects.toMatchObject({
782-code: "EACCES",
783-});
784-} finally {
785-spy.mockRestore();
786-}
787-});
788-789-it("re-throws when stat throws a non-ENOENT error during file scan (line 471)", async () => {
551+it("re-throws when stat throws a non-ENOENT error during file scan", async () => {
790552const root = makeTmpDir();
791553const filePath = path.join(root, "noperm.js");
792554fsSync.writeFileSync(filePath, `export const x = 1;`);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。