Skip to content

Fix critical bugs and add tests for all untested JS sibling files - #283

Merged
loiane merged 1 commit into
mainfrom
loiane/fix-hash-table-bugs-improve-coverage
Sep 24, 2026
Merged

loiane merged 1 commit into
mainfrom
loiane/fix-hash-table-bugs-improve-coverage

Conversation

@loiane

@loiane loiane commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

While reviewing test coverage, discovered that nearly all of the hand-written plain-JS "sibling" implementations (parallel to the tested TypeScript versions) had zero test coverage — they were never require()'d by any test, so bugs could hide indefinitely. This PR adds dedicated tests for every such file and fixes every real bug found along the way.

Overall: 677 tests passing, statement coverage 94.3% → 98.65%.

Bugs fixed

src/08-dictionary-hash/

  • hash-table-linear-probing.js: hash function always returned NaN (a reduce callback returned a function reference instead of invoking it), causing an infinite loop when storing 2+ distinct keys. Also fixed #verifyRemoveSideEffect's scan index not wrapping around the table, which could silently lose a colliding key after remove().
  • hash-table-separate-chaining.js: get()'s return inside forEach never propagated, so it always returned undefined. toString() called JSON.stringify() on the internal LinkedList instance for all but the first bucket, producing "{}" instead of the list's contents.
  • hash-table.js: put() used && instead of || for its null-check (allowed a null key through). remove() used a truthy check that could never remove falsy values (0, '', false). toString() crashed on an empty table and mis-formatted objects in the first bucket.

src/10-tree/

  • fenwick-tree.js / segment-tree.js: missing module.exports — these classes could never be require()'d at all.
  • binary-search-tree.js, avl-tree.js, red-black-tree.js: internal require()s lacked explicit .js extensions, resolving to the .ts siblings instead and throwing at construction time.
  • avl-tree.js & red-black-tree.js: both subclasses declared their own private #root, shadowing the base class's #root used by inherited search/min/max/traversal methods. These were silently broken — search always returned false, min/max always null, traversals were no-ops — for both classes, the whole time.
  • red-black-tree.js: rotation helpers never returned the new subtree root, corrupting the tree on removal-triggered rebalancing. Also fixed a stale parent pointer left after promoting a single child during removal.

src/07-set/set.js

  • has() / getSizeWithoutSizeProperty() called this.#items.hasOwnProperty() directly — throws if a value like "hasOwnProperty" was ever stored, since it shadows the prototype method.

src/06-linked-list/circular-linked-list_.js

  • prepend() mutated a stray public head property instead of the private #head, silently desyncing the list.
  • removeAt() called a nonexistent #removeFromMiddle method — a hard crash for any middle-position removal.
  • remove()/indexOf() contained leftover TypeScript type annotations, which are invalid syntax in a plain .js file and broke module parsing entirely.

queue.js, stack.js, doubly-linked-list_.js

  • toString() called item.toString() on primitives, throwing on undefined items. Switched to String(item) to match the .ts siblings.

src/13-graph/*.js, src/12-trie/trie.js: no .js-specific bugs found — added full test coverage (100% stmts/branch) as a safety net.

Known pre-existing issues found but intentionally left unfixed

(identical in both .js and .ts, so out of scope for this .js-only pass)

  • kruskal.js/.ts: find() uses a falsy parent-pointer check that mistreats vertex 0 as "no parent," which can leave a vertex disconnected from the MST result.
  • segment-tree.js/.ts: the "no overlap" query base case always returns 0, which is only a valid identity for sum, not min/max.
  • red-black-tree.js/.ts: rare duplicate-value delete sequences can produce a structurally invalid BST (fuzz-tested 300+ trials with distinct values — no failures).

Tests added

New __test__ files for every previously-untested .js module: hash-table-js, set-js, trie-js, avl-tree-js, binary-search-tree-js, red-black-tree-js, fenwick-tree-js, segment-tree-js, graph-js, bfs-js, dfs-js, dijkstra-js, floyd-warshall-js, kruskal-js, prim-js, queue-js, stack-js, doubly-linked-list_, circular-linked-list_, plus the earlier linked-list_, deque-js, and comparator tests and rewritten hash-table-collision tests.

- hash-table-linear-probing.js: fix hash function that always returned
  NaN (reduce callback returned the function reference instead of
  invoking it), causing an infinite loop when putting 2+ distinct keys.
  Also fixed the same bug in the unused #djb2HashCode method, and fixed
  #verifyRemoveSideEffect to wrap its scan index so colliding keys that
  wrapped around the table aren't lost after a remove().
- hash-table-separate-chaining.js: fix get() where the callback's
  return inside forEach didn't propagate, so it always returned
  undefined. Fix toString() which JSON.stringify'd the LinkedList
  instance (yielding '{}') for every bucket after the first instead of
  calling its toString().
- Rewrote hash-table-collision.test.ts to test correct behavior instead
  of documenting the bugs, and added collision/wraparound coverage.
- Added new test files for previously under-tested JS sibling modules:
  linked-list_.js, deque.js, comparator.js.
@loiane
loiane merged commit 89594dc into main Sep 24, 2026
1 check passed
@loiane
loiane deleted the loiane/fix-hash-table-bugs-improve-coverage branch September 24, 2026 22:54
@loiane loiane changed the title Fix hash table bugs and improve test coverage for JS sibling files Fix critical bugs and add tests for all untested JS sibling files Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant