diff --git a/bindings/python/tests/test_codelist.py b/bindings/python/tests/test_codelist.py index 8090bfe..b75987d 100644 --- a/bindings/python/tests/test_codelist.py +++ b/bindings/python/tests/test_codelist.py @@ -209,7 +209,7 @@ def test_validate_snomed(self): codelist.validate_codes() self.assertIn("Code 11 is an invalid length for type SNOMED", str(e.exception)) - def test_truncate_icd10_to_3_digits(self): + def test_truncate_icd10_to_3_digits_first(self): codelist = CodeList( name="Test Codelist", codelist_type="ICD10", @@ -227,7 +227,27 @@ def test_truncate_icd10_to_3_digits(self): self.assertEqual(len(codelist.entries()), 3) self.assertIn(("A01", "Typhoid fever, intestinal", None), codelist.entries()) self.assertIn(("A02", "Salmonella infections", None), codelist.entries()) - self.assertIn(("A03", "Random infections, unspecified", "A0311 truncated to 3 digits"), codelist.entries()) + self.assertIn(("A03", "Random infections, unspecified", "A0311 truncated to 3 digits, term first encountered"), codelist.entries()) + + def test_truncate_icd10_to_3_digits_drop_term(self): + codelist = CodeList( + name="Test Codelist", + codelist_type="ICD10", + source="Manually created", + ) + # codelist of various lengths + codelist.add_entry("A01.1", "Typhoid fever, intestinal more complex") + codelist.add_entry("A01", "Typhoid fever, intestinal") + codelist.add_entry("A02", "Salmonella infections") + codelist.add_entry("A0311", "Random infections, unspecified") + + codelist.truncate_to_3_digits(term_management="drop_term") + + ## May be in different order so test entries to account for that + self.assertEqual(len(codelist.entries()), 3) + self.assertIn(("A01", "Typhoid fever, intestinal", None), codelist.entries()) + self.assertIn(("A02", "Salmonella infections", None), codelist.entries()) + self.assertIn(("A03", None, "Truncated to 3 digits, term discarded"), codelist.entries()) def test_invalid_term_management_arg_for_truncate(self): codelist = CodeList( @@ -238,7 +258,7 @@ def test_invalid_term_management_arg_for_truncate(self): codelist.add_entry("A01.1", "Typhoid fever, intestinal more complex") with self.assertRaises(ValueError) as e: codelist.truncate_to_3_digits(term_management="invalid") - self.assertEqual(str(e.exception), "invalid is not known. Valid values are 'first'") + self.assertEqual(str(e.exception), "invalid is not known. Valid values are 'first', 'drop_term'") def test_cannot_truncate_snomed(self): codelist = CodeList( diff --git a/rust/codelist-rs/src/codelist.rs b/rust/codelist-rs/src/codelist.rs index 0a83666..ab32311 100644 --- a/rust/codelist-rs/src/codelist.rs +++ b/rust/codelist-rs/src/codelist.rs @@ -412,12 +412,19 @@ impl CodeList { // The term and comment that goes with it to make the // entry depends on the term_management - let comment = match term_management { - TermManagement::First => Some(format!("{code} truncated to 3 digits")), + let (term, comment) = match term_management { + TermManagement::DropTerm => { + (None, Some("Truncated to 3 digits, term discarded".to_string())) + } + + TermManagement::First => ( + term.clone(), + Some(format!("{code} truncated to 3 digits, term first encountered")), + ), }; // We'll add this one later - adds.push((truncated_code, term.clone(), comment)); + adds.push((truncated_code, term, comment)); } // Add the new three-digit codes @@ -479,6 +486,7 @@ impl CodeList { #[derive(Clone, Copy, PartialEq, Eq)] pub enum TermManagement { + DropTerm, First, } @@ -488,6 +496,7 @@ impl FromStr for TermManagement { /// Map TermManagement from a string fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { + "drop_term" => Ok(TermManagement::DropTerm), "first" => Ok(TermManagement::First), _ => Err(CodeListError::TermManagementNotKnown { term_management: s.to_string() }), } @@ -989,7 +998,68 @@ mod tests { } #[test] - fn test_truncate_to_3_digits_icd10_4_digits() -> Result<(), CodeListError> { + fn test_truncate_to_3_digits_icd10_4_digits_drop_term() -> Result<(), CodeListError> { + let metadata: Metadata = Default::default(); + + let mut expected_codelist = + CodeList::new("test_codelist".to_string(), CodeListType::ICD10, metadata.clone(), None); + expected_codelist.add_entry( + "B01".to_string(), + None, + Some("Truncated to 3 digits, term discarded".to_string()), + )?; + + let mut observed_codelist = + CodeList::new("test_codelist".to_string(), CodeListType::ICD10, metadata, None); + + observed_codelist.add_entry( + "B012".to_string(), + Some("Varicella pneumonia".to_string()), + None, + )?; + + observed_codelist.truncate_to_3_digits(TermManagement::DropTerm)?; + + assert_eq!(observed_codelist, expected_codelist); + + Ok(()) + } + + #[test] + fn test_truncate_to_3_digits_3_and_4_digits_drop_term() -> Result<(), CodeListError> { + let metadata: Metadata = Default::default(); + + let mut expected_codelist = + CodeList::new("test_codelist".to_string(), CodeListType::ICD10, metadata.clone(), None); + expected_codelist.add_entry( + "B01".to_string(), + Some("Varicella [chickenpox]".to_string()), + None, + )?; + + let mut observed_codelist = + CodeList::new("test_codelist".to_string(), CodeListType::ICD10, metadata, None); + + observed_codelist.add_entry( + "B01".to_string(), + Some("Varicella [chickenpox]".to_string()), + None, + )?; + observed_codelist.add_entry( + "B012".to_string(), + Some("Varicella pneumonia".to_string()), + None, + )?; + + observed_codelist.truncate_to_3_digits(TermManagement::DropTerm)?; + + assert_eq!(observed_codelist, expected_codelist); + + Ok(()) + } + + #[test] + fn test_truncate_to_3_digits_icd10_4_digits_first() -> Result<(), CodeListError> { let metadata: Metadata = Default::default(); let mut expected_codelist = @@ -997,7 +1067,7 @@ mod tests { expected_codelist.add_entry( "B01".to_string(), Some("Varicella pneumonia".to_string()), - Some("B012 truncated to 3 digits".to_string()), + Some("B012 truncated to 3 digits, term first encountered".to_string()), )?; let mut observed_codelist = @@ -1017,7 +1087,7 @@ mod tests { } #[test] - fn test_truncate_to_3_digits_3_and_4_digits() -> Result<(), CodeListError> { + fn test_truncate_to_3_digits_3_and_4_digits_first() -> Result<(), CodeListError> { let metadata: Metadata = Default::default(); let mut expected_codelist = diff --git a/rust/codelist-rs/src/errors.rs b/rust/codelist-rs/src/errors.rs index a079bd8..25c4f40 100644 --- a/rust/codelist-rs/src/errors.rs +++ b/rust/codelist-rs/src/errors.rs @@ -133,7 +133,7 @@ pub enum CodeListError { #[error("{codelist_type} cannot be truncated to 3 digits.")] CodeListNotTruncatable { codelist_type: String }, - #[error("{term_management} is not known. Valid values are 'first'")] + #[error("{term_management} is not known. Valid values are 'first', 'drop_term'")] TermManagementNotKnown { term_management: String }, #[error("{codelist_type} cannot be transformed by having X added to the end of it")]