-
Notifications
You must be signed in to change notification settings - Fork 0
Make the locale test stub strict about unexpected variable reads (#489) #502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c0f8ce4
d4b7a59
469a84d
d47939a
af63ce5
efbc241
2e94a59
6fa22ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,29 +4,151 @@ | |
| //! deterministic environment and system locales. | ||
|
|
||
| use netsuke::locale_resolution::{self, LocaleEnvProvider, SystemLocale}; | ||
| use std::collections::HashMap; | ||
|
|
||
| /// Stub environment provider for locale resolution. | ||
| #[derive(Debug, Default, Clone)] | ||
| /// | ||
| /// Answers only the variables it was given, and **panics** on any other key. | ||
| /// | ||
| /// The permissive alternative — returning `None` for anything unrecognized — | ||
| /// hides exactly the change a test double should catch. Were the code under | ||
| /// test altered to read a differently-named variable, through a rename, a typo, | ||
| /// or a new precedence rung, a permissive stub would quietly answer `None` and | ||
| /// the test would still pass while asserting nothing about the new read. The | ||
| /// panic converts that silent pass into a failure naming the unexpected key. | ||
| /// | ||
| /// `Default` is deliberately **not** implemented. On a strict stub it would | ||
| /// mean "deny every read", so `StubEnv::default()` would compile and then | ||
| /// panic at run time for the common "no locale set" case. Requiring | ||
| /// [`StubEnv::without_locale`] makes that intent explicit at compile time. | ||
| #[derive(Debug, Clone)] | ||
| pub struct StubEnv { | ||
| /// Optional locale value to return for `NETSUKE_LOCALE`. | ||
| pub locale: Option<String>, | ||
| values: HashMap<String, String>, | ||
| allowed: Vec<String>, | ||
| } | ||
|
|
||
| impl StubEnv { | ||
| /// Create a stub environment with the provided locale. | ||
| pub fn with_locale(locale: impl Into<String>) -> Self { | ||
| /// Create a stub declaring nothing; every read panics until one is added. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust,should_panic | ||
| /// use netsuke::locale_resolution::LocaleEnvProvider; | ||
| /// use test_support::locale_stubs::StubEnv; | ||
| /// | ||
| /// // Nothing is declared, so any read is a programming error. | ||
| /// StubEnv::strict().var("ANYTHING"); | ||
| /// ``` | ||
| #[must_use] | ||
| pub fn strict() -> Self { | ||
|
Comment on lines
+31
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new public AGENTS.md reference: AGENTS.md:L27-L30 Useful? React with 👍 / 👎.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline test_support/src/locale_stubs.rs --items all --type function,struct,impl --match 'StubEnv|EnvProvider' --view expanded
printf '\n--- StubEnv implementation and EnvProvider contract ---\n'
sed -n '20,155p' test_support/src/locale_stubs.rsLength of output: 662 🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline test_support/src/locale_stubs.rs --items all --type struct,function --match 'StubEnv|strict|without_locale|with_var|allowing|var' --view expanded
printf '\n--- StubEnv implementation and EnvProvider contract ---\n'
sed -n '20,155p' test_support/src/locale_stubs.rsLength of output: 5549
The current
You are interacting with an AI system.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- codegraph: StubEnv public builder map ---'
ast-grep outline test_support/src/locale_stubs.rs \
--items all \
--type struct,function,impl \
--match 'StubEnv|strict|with_locale|without_locale|with_var|allowing' \
--view expanded
printf '%s\n' '--- source: Rustdoc and implementations for all requested builders ---'
sed -n '24,140p' test_support/src/locale_stubs.rsLength of output: 845 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- codegraph: StubEnv public builder map ---'
ast-grep outline test_support/src/locale_stubs.rs \
--items all \
--type struct,function \
--match 'StubEnv|strict|with_locale|without_locale|with_var|allowing' \
--view expanded
printf '%s\n' '--- source: Rustdoc and implementations for all requested builders ---'
sed -n '24,140p' test_support/src/locale_stubs.rsLength of output: 4946
Codegraph analysis confirms that
You are interacting with an AI system.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- Codegraph: StubEnv public builder methods ---'
ast-grep outline test_support/src/locale_stubs.rs \
--items all \
--type struct,impl,function \
--match 'StubEnv|strict|without_locale|with_var|allowing' \
--view expanded
printf '%s\n' '--- Rustdoc and implementations ---'
sed -n '24,140p' test_support/src/locale_stubs.rsLength of output: 806 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- Codegraph: StubEnv declarations ---'
ast-grep outline test_support/src/locale_stubs.rs \
--items all \
--type struct,function \
--match 'StubEnv|strict|without_locale|with_var|allowing' \
--view expanded
printf '%s\n' '--- Rustdoc and builder implementations ---'
sed -n '24,140p' test_support/src/locale_stubs.rsLength of output: 4794
Codegraph analysis confirms that
You are interacting with an AI system. |
||
| Self { | ||
| locale: Some(locale.into()), | ||
| values: HashMap::new(), | ||
| allowed: Vec::new(), | ||
| } | ||
| } | ||
|
|
||
| /// Create a stub answering `NETSUKE_LOCALE` with `locale`. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use netsuke::locale_resolution::LocaleEnvProvider; | ||
| /// use test_support::locale_stubs::StubEnv; | ||
| /// | ||
| /// let env = StubEnv::with_locale("es-ES"); | ||
| /// assert_eq!(env.var("NETSUKE_LOCALE").as_deref(), Some("es-ES")); | ||
| /// ``` | ||
| #[must_use] | ||
| pub fn with_locale(locale: impl Into<String>) -> Self { | ||
| Self::strict().with_var(locale_resolution::NETSUKE_LOCALE_ENV, locale) | ||
| } | ||
|
|
||
| /// Create a stub in which `NETSUKE_LOCALE` is unset but may be read. | ||
| /// | ||
| /// Distinct from a stub that never expected the read at all: an unset | ||
| /// variable is a legitimate case to exercise. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use netsuke::locale_resolution::LocaleEnvProvider; | ||
| /// use test_support::locale_stubs::StubEnv; | ||
| /// | ||
| /// // Declared, so the read is permitted; unset, so it reports `None`. | ||
| /// assert_eq!(StubEnv::without_locale().var("NETSUKE_LOCALE"), None); | ||
| /// ``` | ||
| #[must_use] | ||
| pub fn without_locale() -> Self { | ||
| Self::strict().allowing(locale_resolution::NETSUKE_LOCALE_ENV) | ||
| } | ||
|
|
||
| /// Answer `key` with `value`. | ||
| /// | ||
| /// The most recent declaration for a key wins, so this overrides an earlier | ||
| /// [`StubEnv::allowing`] for the same key. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use netsuke::locale_resolution::LocaleEnvProvider; | ||
| /// use test_support::locale_stubs::StubEnv; | ||
| /// | ||
| /// let env = StubEnv::strict().allowing("X").with_var("X", "set"); | ||
| /// assert_eq!(env.var("X").as_deref(), Some("set")); | ||
| /// ``` | ||
| #[must_use] | ||
| pub fn with_var(mut self, key: impl Into<String>, value: impl Into<String>) -> Self { | ||
| let name = key.into(); | ||
| if !self.allowed.iter().any(|allowed| allowed == &name) { | ||
| self.allowed.push(name.clone()); | ||
| } | ||
| self.values.insert(name, value.into()); | ||
| self | ||
| } | ||
|
|
||
| /// Permit `key` to be read, reporting it as unset. | ||
| /// | ||
| /// Needed because an unset variable is a legitimate case to test, and must | ||
| /// be distinguishable from a variable the test never expected to be read. | ||
| /// | ||
| /// The most recent declaration for a key wins, so this clears a value set | ||
| /// by an earlier [`StubEnv::with_var`]. Were it merely to append to the | ||
| /// permitted list, the builder would read as declaring the key unset while | ||
| /// still answering with the old value. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use netsuke::locale_resolution::LocaleEnvProvider; | ||
| /// use test_support::locale_stubs::StubEnv; | ||
| /// | ||
| /// let env = StubEnv::strict().with_var("X", "set").allowing("X"); | ||
| /// assert_eq!(env.var("X"), None); | ||
| /// ``` | ||
| #[must_use] | ||
| pub fn allowing(mut self, key: impl Into<String>) -> Self { | ||
| let name = key.into(); | ||
| self.values.remove(&name); | ||
| if !self.allowed.iter().any(|allowed| allowed == &name) { | ||
| self.allowed.push(name); | ||
| } | ||
| self | ||
| } | ||
| } | ||
|
|
||
| impl LocaleEnvProvider for StubEnv { | ||
| fn var(&self, key: &str) -> Option<String> { | ||
| if key == locale_resolution::NETSUKE_LOCALE_ENV { | ||
| return self.locale.clone(); | ||
| } | ||
| None | ||
| assert!( | ||
| self.allowed.iter().any(|allowed| allowed == key), | ||
| concat!( | ||
| "StubEnv was asked for {:?}, which the test did not declare. ", | ||
| "Declare it with `.with_var(..)` or `.allowing(..)` if the read ", | ||
| "is intended; otherwise the code under test is reading a ", | ||
| "variable the test does not know about." | ||
| ), | ||
| key | ||
| ); | ||
|
Comment on lines
+141
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No test introduced by this change calls AGENTS.md reference: AGENTS.md:L64-L70 Useful? React with 👍 / 👎.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Current commit =='
git rev-parse HEAD
printf '%s\n' '== Rust source map for StubEnv module =='
ast-grep outline test_support/src/locale_stubs.rs --items all
printf '%s\n' '== Test-support source map =='
ast-grep outline test_support --items all --type function
printf '%s\n' '== StubEnv construction and undeclared-read test candidates =='
rg -n --glob '*.rs' -C 4 \
'(StubEnv::(strict|with_locale|without_locale)|\.var\(".*"\)|should_panic|assert_panics|did not declare|unexpected.*read)' \
test_support tests
printf '%s\n' '== Attribute-to-function codegraph candidates =='
ast-grep run --lang rust --pattern '#[should_panic]
fn $NAME($$$) { $$$ }' test_support tests || trueLength of output: 17935
The latest commit,
You are interacting with an AI system.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Current revision =='
git rev-parse HEAD
printf '%s\n' '== Relevant Rust symbol map =='
ast-grep outline test_support/src/locale_stubs.rs --items all
ast-grep outline tests/locale_stub_strictness_tests.rs --items all
printf '%s\n' '== Undeclared-read test functions =='
ast-grep run --lang rust \
--pattern '#[should_panic]
fn $NAME($$$) {
$$$
}' \
tests/locale_stub_strictness_tests.rs || true
printf '%s\n' '== Focused codegraph edges =='
rg -n -C 5 --glob '*.rs' \
'undeclared_read_panics|the_panic_names_the_offending_key|StubEnv::strict\(\)\.var\(|fn var\(&self, key: &str\)|did not declare' \
test_support/src/locale_stubs.rs tests/locale_stub_strictness_tests.rsLength of output: 5274
Codegraph analysis of revision
The call reaches
🧠 Learnings usedYou are interacting with an AI system.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai Has this now been resolved in the latest commit? Use codegraph analysis to determine your answer. If this comment is now resolved, please reply confirming this. Otherwise, please provide a follow-up recommendation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Current revision =='
git rev-parse HEAD
printf '%s\n' '== Relevant symbol maps =='
ast-grep outline test_support/src/locale_stubs.rs --items all
ast-grep outline tests/locale_stub_strictness_tests.rs --items all
printf '%s\n' '== Undeclared-read test and implementation edges =='
rg -n -C 6 --glob '*.rs' \
'fn undeclared_read_panics\b|fn the_panic_names_the_offending_key\b|StubEnv::strict\(\)\.var\(|fn var\(&self, key: &str\)|which the test did not declare|self\.allowed\.iter\(\)\.any' \
test_support/src/locale_stubs.rs tests/locale_stub_strictness_tests.rs
printf '%s\n' '== Structural test candidates =='
ast-grep run --lang rust \
--pattern '#[should_panic(expected = $MESSAGE)]
fn $NAME($$$) {
$$$
}' \
tests/locale_stub_strictness_tests.rs || trueLength of output: 7382
Codegraph analysis of revision
That call reaches
🧠 Learnings usedYou are interacting with an AI system. |
||
| self.values.get(key).cloned() | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Seeds for failure cases proptest has generated in the past. It is | ||
| # automatically read and these particular cases re-run before any | ||
| # novel cases are generated. | ||
| # | ||
| # It is recommended to check this file in to source control so that | ||
| # everyone who runs the test benefits from these saved cases. | ||
| # Recorded while mutation-testing the property (allowing's value clear was | ||
| # disabled to prove the test detects it), not from a defect in StubEnv. | ||
| cc 04881a9256003f8215b73836a16209c1713861db70e59925b4d1ca3ea1cebec3 # shrinks to declarations = [Set("A", "a"), Allow("A")] |
Uh oh!
There was an error while loading. Please reload this page.