fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) - #614

Merged
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion
Mar 29, 2026
Merged

fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607)#614
Chemaclass merged 2 commits into
TypedDevs:mainfrom
SauronBot:fix/spy-echo-printf-recursion

Conversation

@SauronBot

Copy link
Copy Markdown
Contributor

Issue

Closes#607

Background

Spying on echo or printf caused bashunit to hang indefinitely. The spy generates a shell function that overrides the command, but the generated body itself used bare echo and printf calls — which called back into the spy, triggering infinite recursion and process explosion.

Additionally, bashunit::helper::normalize_variable_name uses echo to return its value, so spy assertions (which call that helper) were also broken when echo was spied upon.

Goal

Prevent infinite recursion when spying on shell builtins echo or printf, allowing tests that spy on these commands to complete normally.

Changes

  • src/test_doubles.sh: Use builtin echo and builtin printf inside the eval'd spy function body in bashunit::spy, and builtin echo in the no-arg form of bashunit::mock
  • src/helpers.sh: Use builtin echo in bashunit::helper::normalize_variable_name so spy assertions remain functional even when echo is spied upon
  • tests/functional/doubles_test.sh: Add two functional tests verifying that spying on echo and printf completes without hanging
  • tests/functional/fixtures/echo_function.sh: Fixture with a function that calls echo
  • tests/functional/fixtures/printf_function.sh: Fixture with a function that calls printf

@ChemaclassChemaclass added the bug Something isn't working label Mar 29, 2026
…n when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because
the generated spy function called back into itself through bashunit's
internal use of these builtins.
Changes:
- Use 'builtin echo' and 'builtin printf' inside the eval'd spy function
body in bashunit::spy to prevent recursive calls when spying on echo
or printf
- Use 'builtin echo' in bashunit::mock's no-arg form for the same reason
- Use 'builtin echo' in bashunit::helper::normalize_variable_name so that
spy assertions remain functional even when echo is spied upon
- Add functional tests (with fixtures) verifying that spying on echo and
printf completes without hanging
FixesTypedDevs#607
@SauronBot
SauronBotforce-pushed the fix/spy-echo-printf-recursion branch from 9f739d0 to cd300ceCompareMarch 29, 2026 19:11
@Chemaclass
Chemaclass merged commit 52368d3 into TypedDevs:mainMar 29, 2026
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spying on "echo" breaks bashunit

2 participants

@SauronBot@Chemaclass