| <!DOCTYPE HTML> |
| <html lang="en" class="light sidebar-visible" dir="ltr"> |
| <head> |
| <!-- Book generated using mdBook --> |
| <meta charset="UTF-8"> |
| <title>Code Coverage - rules_rust</title> |
| |
| |
| <!-- Custom HTML head --> |
| |
| <meta name="description" content=""> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <meta name="theme-color" content="#ffffff"> |
| |
| <link rel="icon" href="favicon.svg"> |
| <link rel="shortcut icon" href="favicon.png"> |
| <link rel="stylesheet" href="css/variables.css"> |
| <link rel="stylesheet" href="css/general.css"> |
| <link rel="stylesheet" href="css/chrome.css"> |
| <link rel="stylesheet" href="css/print.css" media="print"> |
| |
| <!-- Fonts --> |
| <link rel="stylesheet" href="FontAwesome/css/font-awesome.css"> |
| <link rel="stylesheet" href="fonts/fonts.css"> |
| |
| <!-- Highlight.js Stylesheets --> |
| <link rel="stylesheet" href="highlight.css"> |
| <link rel="stylesheet" href="tomorrow-night.css"> |
| <link rel="stylesheet" href="ayu-highlight.css"> |
| |
| <!-- Custom theme stylesheets --> |
| |
| |
| <!-- Provide site root to javascript --> |
| <script> |
| var path_to_root = ""; |
| var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light"; |
| </script> |
| <!-- Start loading toc.js asap --> |
| <script src="toc.js"></script> |
| </head> |
| <body> |
| <div id="body-container"> |
| <!-- Work around some values being stored in localStorage wrapped in quotes --> |
| <script> |
| try { |
| var theme = localStorage.getItem('mdbook-theme'); |
| var sidebar = localStorage.getItem('mdbook-sidebar'); |
| |
| if (theme.startsWith('"') && theme.endsWith('"')) { |
| localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); |
| } |
| |
| if (sidebar.startsWith('"') && sidebar.endsWith('"')) { |
| localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); |
| } |
| } catch (e) { } |
| </script> |
| |
| <!-- Set the theme before any content is loaded, prevents flash --> |
| <script> |
| var theme; |
| try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } |
| if (theme === null || theme === undefined) { theme = default_theme; } |
| const html = document.documentElement; |
| html.classList.remove('light') |
| html.classList.add(theme); |
| html.classList.add("js"); |
| </script> |
| |
| <input type="checkbox" id="sidebar-toggle-anchor" class="hidden"> |
| |
| <!-- Hide / unhide sidebar before it is displayed --> |
| <script> |
| var sidebar = null; |
| var sidebar_toggle = document.getElementById("sidebar-toggle-anchor"); |
| if (document.body.clientWidth >= 1080) { |
| try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } |
| sidebar = sidebar || 'visible'; |
| } else { |
| sidebar = 'hidden'; |
| } |
| sidebar_toggle.checked = sidebar === 'visible'; |
| html.classList.remove('sidebar-visible'); |
| html.classList.add("sidebar-" + sidebar); |
| </script> |
| |
| <nav id="sidebar" class="sidebar" aria-label="Table of contents"> |
| <!-- populated by js --> |
| <mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox> |
| <noscript> |
| <iframe class="sidebar-iframe-outer" src="toc.html"></iframe> |
| </noscript> |
| <div id="sidebar-resize-handle" class="sidebar-resize-handle"> |
| <div class="sidebar-resize-indicator"></div> |
| </div> |
| </nav> |
| |
| <div id="page-wrapper" class="page-wrapper"> |
| |
| <div class="page"> |
| <div id="menu-bar-hover-placeholder"></div> |
| <div id="menu-bar" class="menu-bar sticky"> |
| <div class="left-buttons"> |
| <label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar"> |
| <i class="fa fa-bars"></i> |
| </label> |
| <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list"> |
| <i class="fa fa-paint-brush"></i> |
| </button> |
| <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu"> |
| <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li> |
| <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li> |
| </ul> |
| <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar"> |
| <i class="fa fa-search"></i> |
| </button> |
| </div> |
| |
| <h1 class="menu-title">rules_rust</h1> |
| |
| <div class="right-buttons"> |
| <a href="print.html" title="Print this book" aria-label="Print this book"> |
| <i id="print-button" class="fa fa-print"></i> |
| </a> |
| <a href="https://github.com/bazelbuild/rules_rust" title="Git repository" aria-label="Git repository"> |
| <i id="git-repository-button" class="fa fa-github"></i> |
| </a> |
| |
| </div> |
| </div> |
| |
| <div id="search-wrapper" class="hidden"> |
| <form id="searchbar-outer" class="searchbar-outer"> |
| <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header"> |
| </form> |
| <div id="searchresults-outer" class="searchresults-outer hidden"> |
| <div id="searchresults-header" class="searchresults-header"></div> |
| <ul id="searchresults"> |
| </ul> |
| </div> |
| </div> |
| |
| <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> |
| <script> |
| document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); |
| document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); |
| Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) { |
| link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); |
| }); |
| </script> |
| |
| <div id="content" class="content"> |
| <main> |
| <h1 id="code-coverage"><a class="header" href="#code-coverage">Code Coverage</a></h1> |
| <p>Rules Rust supports collecting code coverage data using <code>bazel coverage</code>, leveraging LLVM's source-based coverage instrumentation.</p> |
| <h2 id="basic-usage"><a class="header" href="#basic-usage">Basic Usage</a></h2> |
| <pre><code class="language-sh">bazel coverage //my_project/... |
| </code></pre> |
| <p>This instruments all targets matching the default <code>--instrumentation_filter</code> and produces an LCOV report at <code>bazel-out/_coverage/_coverage_report.dat</code>.</p> |
| <h2 id="controlling-instrumentation"><a class="header" href="#controlling-instrumentation">Controlling Instrumentation</a></h2> |
| <p>Rules Rust respects Bazel's standard <a href="https://bazel.build/reference/command-line-reference#flag--instrumentation_filter"><code>--instrumentation_filter</code></a> flag to control which targets get compiled with <code>-Cinstrument-coverage</code>. Only targets whose label matches the filter are instrumented, consistent with how coverage works for other languages (C++, Java).</p> |
| <h3 id="recommended-bazelrc-settings"><a class="header" href="#recommended-bazelrc-settings">Recommended <code>.bazelrc</code> Settings</a></h3> |
| <p>For projects with vendored or third-party dependencies, restrict instrumentation to workspace targets to avoid unnecessary recompilation:</p> |
| <pre><code class="language-text">coverage --instrumentation_filter=^// |
| </code></pre> |
| <p>To further exclude specific directories:</p> |
| <pre><code class="language-text">coverage --instrumentation_filter=^//,-^//third_party |
| </code></pre> |
| <h3 id="rust_test-with-a-crate-attribute"><a class="header" href="#rust_test-with-a-crate-attribute"><code>rust_test</code> with a <code>crate</code> attribute</a></h3> |
| <p>When a <code>rust_test</code> target uses the <code>crate</code> attribute, Rust compiles the library source code directly into the test binary. Rules Rust automatically checks whether the underlying crate should be instrumented, so library code compiled into the test binary produces coverage data without needing <code>--instrument_test_targets</code>.</p> |
| <p>Note: because the entire crate (including <code>#[cfg(test)]</code> code) is compiled as one unit, test-specific code in the crate will also be instrumented. This is a known inconsistency with the usual Bazel convention where test code is only instrumented when <code>--instrument_test_targets</code> is set.</p> |
| <h3 id="--instrument_test_targets"><a class="header" href="#--instrument_test_targets"><code>--instrument_test_targets</code></a></h3> |
| <p>By default, Bazel excludes test targets from instrumentation. If you want coverage of the test code itself (not just the libraries it exercises), add:</p> |
| <pre><code class="language-text">coverage --instrument_test_targets |
| </code></pre> |
| <h3 id="flags-summary"><a class="header" href="#flags-summary">Flags Summary</a></h3> |
| <div class="table-wrapper"><table><thead><tr><th>Flag</th><th>Purpose</th></tr></thead><tbody> |
| <tr><td><code>--instrumentation_filter=<regex></code></td><td>Controls which targets are instrumented. Default: <code>-/javatests[/:],-/test/java[/:]</code></td></tr> |
| <tr><td><code>--instrument_test_targets</code></td><td>Also instrument test targets. Not required for library coverage via <code>rust_test</code> with <code>crate</code>.</td></tr> |
| <tr><td><code>--combined_report=lcov</code></td><td>Produce a combined LCOV report (set by default with <code>bazel coverage</code>).</td></tr> |
| </tbody></table> |
| </div> |
| </main> |
| |
| <nav class="nav-wrapper" aria-label="Page navigation"> |
| <!-- Mobile navigation buttons --> |
| <a rel="prev" href="crate_universe_bzlmod.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> |
| <i class="fa fa-angle-left"></i> |
| </a> |
| |
| <a rel="next prefetch" href="upstream_tooling.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> |
| <i class="fa fa-angle-right"></i> |
| </a> |
| |
| <div style="clear: both"></div> |
| </nav> |
| </div> |
| </div> |
| |
| <nav class="nav-wide-wrapper" aria-label="Page navigation"> |
| <a rel="prev" href="crate_universe_bzlmod.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> |
| <i class="fa fa-angle-left"></i> |
| </a> |
| |
| <a rel="next prefetch" href="upstream_tooling.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> |
| <i class="fa fa-angle-right"></i> |
| </a> |
| </nav> |
| |
| </div> |
| |
| |
| |
| |
| <script> |
| window.playground_copyable = true; |
| </script> |
| |
| |
| <script src="elasticlunr.min.js"></script> |
| <script src="mark.min.js"></script> |
| <script src="searcher.js"></script> |
| |
| <script src="clipboard.min.js"></script> |
| <script src="highlight.js"></script> |
| <script src="book.js"></script> |
| |
| <!-- Custom JS scripts --> |
| |
| |
| </div> |
| </body> |
| </html> |