diff --git a/exercises/practice/protein-translation/.meta/additional-tests.json b/exercises/practice/protein-translation/.meta/additional-tests.json new file mode 100644 index 000000000..530dc1483 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/additional-tests.json @@ -0,0 +1,182 @@ +[ + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "methionine", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "AUG" + }, + "expected": "Some(\"methionine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "cysteine tgt", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "UGU" + }, + "expected": "Some(\"cysteine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "stop", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "UAA" + }, + "expected": "Some(\"stop codon\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "valine", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "GUU" + }, + "expected": "Some(\"valine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "isoleucine", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "AUU" + }, + "expected": "Some(\"isoleucine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "arginine cga", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "CGA" + }, + "expected": "Some(\"arginine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "arginine aga", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "AGA" + }, + "expected": "Some(\"arginine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "arginine agg", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "AGG" + }, + "expected": "Some(\"arginine\")" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "empty is invalid", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "" + }, + "expected": "None" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "x is not shorthand so is invalid", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "VWX" + }, + "expected": "None" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "too short is invalid", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "AU" + }, + "expected": "None" + }, + { + "uuid": "ecafab60-89f2-4680-9286-56b423e8a7b9", + "description": "too long is invalid", + "comments": [ + "The original design of the exercise deviates from problem-specifications", + "by having a name_for function for individual codons.", + "Upstreaming is impossible as it would change the design of the exercise.", + "Omitting them would leave the function untested, which would be confusing." + ], + "property": "name_for", + "input": { + "name": "ATTA" + }, + "expected": "None" + } +] diff --git a/exercises/practice/protein-translation/.meta/test_template.tera b/exercises/practice/protein-translation/.meta/test_template.tera new file mode 100644 index 000000000..e124dbac1 --- /dev/null +++ b/exercises/practice/protein-translation/.meta/test_template.tera @@ -0,0 +1,68 @@ +use protein_translation::*; + +{% for test in cases %} +{# custom name_for tests are first, of_rna is supposed to build on it #} +{% if test.property != "name_for" %}{% continue %}{% endif %} +#[test] +#[ignore] +fn {{ test.description | snake_case }}() { + let info = parse(make_pairs()); + assert_eq!(info.name_for({{ test.input.name | json_encode() }}), {{ test.expected }}); +} +{% endfor -%} + +{% for test in cases %} +{% if test.property != "proteins" %}{% continue %}{% endif %} +#[test] +#[ignore] +fn {{ test.description | snake_case }}() { + let info = parse(make_pairs()); + assert_eq!( + info.of_rna({{ test.input.strand | json_encode() }}), + {% if test.expected is object %} + None + {% else %} + Some(vec![ + {% for s in test.expected %} + "{{ s | lower }}" {% if not loop.last %} , {% endif %} + {% endfor %} + ]) + {% endif %}, + ); +} +{% endfor -%} + +// The input data constructor. Returns a list of codon, name pairs. +fn make_pairs() -> Vec<(&'static str, &'static str)> { + let grouped = vec![ + ("isoleucine", vec!["AUU", "AUC", "AUA"]), + ("valine", vec!["GUU", "GUC", "GUA", "GUG"]), + ("phenylalanine", vec!["UUU", "UUC"]), + ("methionine", vec!["AUG"]), + ("cysteine", vec!["UGU", "UGC"]), + ("alanine", vec!["GCU", "GCC", "GCA", "GCG"]), + ("glycine", vec!["GGU", "GGC", "GGA", "GGG"]), + ("proline", vec!["CCU", "CCC", "CCA", "CCG"]), + ("threonine", vec!["ACU", "ACC", "ACA", "ACG"]), + ("serine", vec!["UCU", "UCC", "UCA", "UCG"]), + ("tyrosine", vec!["UAU", "UAC"]), + ("tryptophan", vec!["UGG"]), + ("glutamine", vec!["CAA", "CAG"]), + ("asparagine", vec!["AAU", "AAC"]), + ("histidine", vec!["CAU", "CAC"]), + ("glutamic acid", vec!["GAA", "GAG"]), + ("aspartic acid", vec!["GAU", "GAC"]), + ("lysine", vec!["AAA", "AAG"]), + ("arginine", vec!["CGU", "CGC", "CGA", "CGG", "AGA", "AGG"]), + ("leucine", vec!["UUA", "UUG"]), + ("stop codon", vec!["UAA", "UAG", "UGA"]), + ]; + let mut pairs = Vec::<(&'static str, &'static str)>::new(); + for (name, codons) in grouped.into_iter() { + for codon in codons { + pairs.push((codon, name)); + } + } + pairs.sort_by(|&(_, a), &(_, b)| a.cmp(b)); + pairs +} diff --git a/exercises/practice/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml index be690e975..804b446e6 100644 --- a/exercises/practice/protein-translation/.meta/tests.toml +++ b/exercises/practice/protein-translation/.meta/tests.toml @@ -1,3 +1,102 @@ -# This is an auto-generated file. Regular comments will be removed when this -# file is regenerated. Regenerating will not touch any manually added keys, -# so comments can be added in a "comment" key. +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[2c44f7bf-ba20-43f7-a3bf-f2219c0c3f98] +description = "Empty RNA sequence results in no proteins" + +[96d3d44f-34a2-4db4-84cd-fff523e069be] +description = "Methionine RNA sequence" + +[1b4c56d8-d69f-44eb-be0e-7b17546143d9] +description = "Phenylalanine RNA sequence 1" + +[81b53646-bd57-4732-b2cb-6b1880e36d11] +description = "Phenylalanine RNA sequence 2" + +[42f69d4f-19d2-4d2c-a8b0-f0ae9ee1b6b4] +description = "Leucine RNA sequence 1" + +[ac5edadd-08ed-40a3-b2b9-d82bb50424c4] +description = "Leucine RNA sequence 2" + +[8bc36e22-f984-44c3-9f6b-ee5d4e73f120] +description = "Serine RNA sequence 1" + +[5c3fa5da-4268-44e5-9f4b-f016ccf90131] +description = "Serine RNA sequence 2" + +[00579891-b594-42b4-96dc-7ff8bf519606] +description = "Serine RNA sequence 3" + +[08c61c3b-fa34-4950-8c4a-133945570ef6] +description = "Serine RNA sequence 4" + +[54e1e7d8-63c0-456d-91d2-062c72f8eef5] +description = "Tyrosine RNA sequence 1" + +[47bcfba2-9d72-46ad-bbce-22f7666b7eb1] +description = "Tyrosine RNA sequence 2" + +[3a691829-fe72-43a7-8c8e-1bd083163f72] +description = "Cysteine RNA sequence 1" + +[1b6f8a26-ca2f-43b8-8262-3ee446021767] +description = "Cysteine RNA sequence 2" + +[1e91c1eb-02c0-48a0-9e35-168ad0cb5f39] +description = "Tryptophan RNA sequence" + +[e547af0b-aeab-49c7-9f13-801773a73557] +description = "STOP codon RNA sequence 1" + +[67640947-ff02-4f23-a2ef-816f8a2ba72e] +description = "STOP codon RNA sequence 2" + +[9c2ad527-ebc9-4ace-808b-2b6447cb54cb] +description = "STOP codon RNA sequence 3" + +[f4d9d8ee-00a8-47bf-a1e3-1641d4428e54] +description = "Sequence of two protein codons translates into proteins" + +[dd22eef3-b4f1-4ad6-bb0b-27093c090a9d] +description = "Sequence of two different protein codons translates into proteins" + +[d0f295df-fb70-425c-946c-ec2ec185388e] +description = "Translate RNA strand into correct protein list" + +[e30e8505-97ec-4e5f-a73e-5726a1faa1f4] +description = "Translation stops if STOP codon at beginning of sequence" + +[5358a20b-6f4c-4893-bce4-f929001710f3] +description = "Translation stops if STOP codon at end of two-codon sequence" + +[ba16703a-1a55-482f-bb07-b21eef5093a3] +description = "Translation stops if STOP codon at end of three-codon sequence" + +[4089bb5a-d5b4-4e71-b79e-b8d1f14a2911] +description = "Translation stops if STOP codon in middle of three-codon sequence" + +[2c2a2a60-401f-4a80-b977-e0715b23b93d] +description = "Translation stops if STOP codon in middle of six-codon sequence" + +[1e75ea2a-f907-4994-ae5c-118632a1cb0f] +description = "Non-existing codon can't translate" +include = false + +[9eac93f3-627a-4c90-8653-6d0a0595bc6f] +description = "Unknown amino acids, not part of a codon, can't translate" +reimplements = "1e75ea2a-f907-4994-ae5c-118632a1cb0f" + +[9d73899f-e68e-4291-b1e2-7bf87c00f024] +description = "Incomplete RNA sequence can't translate" + +[43945cf7-9968-402d-ab9f-b8a28750b050] +description = "Incomplete RNA sequence can translate if valid until a STOP codon" diff --git a/exercises/practice/protein-translation/tests/protein-translation.rs b/exercises/practice/protein-translation/tests/protein-translation.rs index d7c0369d0..a8ece5736 100644 --- a/exercises/practice/protein-translation/tests/protein-translation.rs +++ b/exercises/practice/protein-translation/tests/protein-translation.rs @@ -1,125 +1,304 @@ -use protein_translation as proteins; +use protein_translation::*; #[test] fn methionine() { - let info = proteins::parse(make_pairs()); + let info = parse(make_pairs()); assert_eq!(info.name_for("AUG"), Some("methionine")); } #[test] #[ignore] fn cysteine_tgt() { - let info = proteins::parse(make_pairs()); + let info = parse(make_pairs()); assert_eq!(info.name_for("UGU"), Some("cysteine")); } #[test] #[ignore] fn stop() { - let info = proteins::parse(make_pairs()); + let info = parse(make_pairs()); assert_eq!(info.name_for("UAA"), Some("stop codon")); } #[test] #[ignore] fn valine() { - let info = proteins::parse(make_pairs()); + let info = parse(make_pairs()); assert_eq!(info.name_for("GUU"), Some("valine")); } #[test] #[ignore] fn isoleucine() { - let info = proteins::parse(make_pairs()); + let info = parse(make_pairs()); assert_eq!(info.name_for("AUU"), Some("isoleucine")); } #[test] #[ignore] -fn arginine_name() { - let info = proteins::parse(make_pairs()); +fn arginine_cga() { + let info = parse(make_pairs()); assert_eq!(info.name_for("CGA"), Some("arginine")); +} + +#[test] +#[ignore] +fn arginine_aga() { + let info = parse(make_pairs()); assert_eq!(info.name_for("AGA"), Some("arginine")); +} + +#[test] +#[ignore] +fn arginine_agg() { + let info = parse(make_pairs()); assert_eq!(info.name_for("AGG"), Some("arginine")); } #[test] #[ignore] fn empty_is_invalid() { - let info = proteins::parse(make_pairs()); - assert!(info.name_for("").is_none()); + let info = parse(make_pairs()); + assert_eq!(info.name_for(""), None); } #[test] #[ignore] fn x_is_not_shorthand_so_is_invalid() { - let info = proteins::parse(make_pairs()); - assert!(info.name_for("VWX").is_none()); + let info = parse(make_pairs()); + assert_eq!(info.name_for("VWX"), None); } #[test] #[ignore] fn too_short_is_invalid() { - let info = proteins::parse(make_pairs()); - assert!(info.name_for("AU").is_none()); + let info = parse(make_pairs()); + assert_eq!(info.name_for("AU"), None); } #[test] #[ignore] fn too_long_is_invalid() { - let info = proteins::parse(make_pairs()); - assert!(info.name_for("ATTA").is_none()); + let info = parse(make_pairs()); + assert_eq!(info.name_for("ATTA"), None); +} + +#[test] +#[ignore] +fn empty_rna_sequence_results_in_no_proteins() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna(""), Some(vec![]),); +} + +#[test] +#[ignore] +fn methionine_rna_sequence() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("AUG"), Some(vec!["methionine"]),); +} + +#[test] +#[ignore] +fn phenylalanine_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UUU"), Some(vec!["phenylalanine"]),); +} + +#[test] +#[ignore] +fn phenylalanine_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UUC"), Some(vec!["phenylalanine"]),); +} + +#[test] +#[ignore] +fn leucine_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UUA"), Some(vec!["leucine"]),); +} + +#[test] +#[ignore] +fn leucine_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UUG"), Some(vec!["leucine"]),); +} + +#[test] +#[ignore] +fn serine_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UCU"), Some(vec!["serine"]),); +} + +#[test] +#[ignore] +fn serine_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UCC"), Some(vec!["serine"]),); +} + +#[test] +#[ignore] +fn serine_rna_sequence_3() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UCA"), Some(vec!["serine"]),); +} + +#[test] +#[ignore] +fn serine_rna_sequence_4() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UCG"), Some(vec!["serine"]),); +} + +#[test] +#[ignore] +fn tyrosine_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UAU"), Some(vec!["tyrosine"]),); } #[test] #[ignore] -fn translates_rna_strand_into_correct_protein() { - let info = proteins::parse(make_pairs()); +fn tyrosine_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UAC"), Some(vec!["tyrosine"]),); +} + +#[test] +#[ignore] +fn cysteine_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGU"), Some(vec!["cysteine"]),); +} + +#[test] +#[ignore] +fn cysteine_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGC"), Some(vec!["cysteine"]),); +} + +#[test] +#[ignore] +fn tryptophan_rna_sequence() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGG"), Some(vec!["tryptophan"]),); +} + +#[test] +#[ignore] +fn stop_codon_rna_sequence_1() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UAA"), Some(vec![]),); +} + +#[test] +#[ignore] +fn stop_codon_rna_sequence_2() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UAG"), Some(vec![]),); +} + +#[test] +#[ignore] +fn stop_codon_rna_sequence_3() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGA"), Some(vec![]),); +} + +#[test] +#[ignore] +fn sequence_of_two_protein_codons_translates_into_proteins() { + let info = parse(make_pairs()); + assert_eq!( + info.of_rna("UUUUUU"), + Some(vec!["phenylalanine", "phenylalanine"]), + ); +} + +#[test] +#[ignore] +fn sequence_of_two_different_protein_codons_translates_into_proteins() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UUAUUG"), Some(vec!["leucine", "leucine"]),); +} + +#[test] +#[ignore] +fn translate_rna_strand_into_correct_protein_list() { + let info = parse(make_pairs()); assert_eq!( info.of_rna("AUGUUUUGG"), - Some(vec!["methionine", "phenylalanine", "tryptophan"]) + Some(vec!["methionine", "phenylalanine", "tryptophan"]), ); } #[test] #[ignore] -fn stops_translation_if_stop_codon_present() { - let info = proteins::parse(make_pairs()); +fn translation_stops_if_stop_codon_at_beginning_of_sequence() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UAGUGG"), Some(vec![]),); +} + +#[test] +#[ignore] +fn translation_stops_if_stop_codon_at_end_of_two_codon_sequence() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGGUAG"), Some(vec!["tryptophan"]),); +} + +#[test] +#[ignore] +fn translation_stops_if_stop_codon_at_end_of_three_codon_sequence() { + let info = parse(make_pairs()); assert_eq!( info.of_rna("AUGUUUUAA"), - Some(vec!["methionine", "phenylalanine"]) + Some(vec!["methionine", "phenylalanine"]), ); } #[test] #[ignore] -fn stops_translation_of_longer_strand() { - let info = proteins::parse(make_pairs()); +fn translation_stops_if_stop_codon_in_middle_of_three_codon_sequence() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("UGGUAGUGG"), Some(vec!["tryptophan"]),); +} + +#[test] +#[ignore] +fn translation_stops_if_stop_codon_in_middle_of_six_codon_sequence() { + let info = parse(make_pairs()); assert_eq!( info.of_rna("UGGUGUUAUUAAUGGUUU"), - Some(vec!["tryptophan", "cysteine", "tyrosine"]) + Some(vec!["tryptophan", "cysteine", "tyrosine"]), ); } #[test] #[ignore] -fn invalid_codons() { - let info = proteins::parse(make_pairs()); - assert!(info.of_rna("CARROT").is_none()); +fn unknown_amino_acids_not_part_of_a_codon_can_t_translate() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("XYZ"), None,); } #[test] #[ignore] -fn invalid_length() { - let info = proteins::parse(make_pairs()); - assert!(info.of_rna("AUGUA").is_none()); +fn incomplete_rna_sequence_can_t_translate() { + let info = parse(make_pairs()); + assert_eq!(info.of_rna("AUGU"), None,); } #[test] #[ignore] -fn valid_stopped_rna() { - let info = proteins::parse(make_pairs()); - assert_eq!(info.of_rna("AUGUAAASDF"), Some(vec!["methionine"])); +fn incomplete_rna_sequence_can_translate_if_valid_until_a_stop_codon() { + let info = parse(make_pairs()); + assert_eq!( + info.of_rna("UUCUUCUAAUGGU"), + Some(vec!["phenylalanine", "phenylalanine"]), + ); } // The input data constructor. Returns a list of codon, name pairs. @@ -134,7 +313,7 @@ fn make_pairs() -> Vec<(&'static str, &'static str)> { ("glycine", vec!["GGU", "GGC", "GGA", "GGG"]), ("proline", vec!["CCU", "CCC", "CCA", "CCG"]), ("threonine", vec!["ACU", "ACC", "ACA", "ACG"]), - ("serine", vec!["AGU", "AGC"]), + ("serine", vec!["UCU", "UCC", "UCA", "UCG"]), ("tyrosine", vec!["UAU", "UAC"]), ("tryptophan", vec!["UGG"]), ("glutamine", vec!["CAA", "CAG"]), @@ -144,6 +323,7 @@ fn make_pairs() -> Vec<(&'static str, &'static str)> { ("aspartic acid", vec!["GAU", "GAC"]), ("lysine", vec!["AAA", "AAG"]), ("arginine", vec!["CGU", "CGC", "CGA", "CGG", "AGA", "AGG"]), + ("leucine", vec!["UUA", "UUG"]), ("stop codon", vec!["UAA", "UAG", "UGA"]), ]; let mut pairs = Vec::<(&'static str, &'static str)>::new(); diff --git a/problem-specifications b/problem-specifications index 381bb40d6..72d52dd52 160000 --- a/problem-specifications +++ b/problem-specifications @@ -1 +1 @@ -Subproject commit 381bb40d6e01d175be183eece44e60897dc9b12d +Subproject commit 72d52dd5287ef7ec8c2fbb56889c220476f8baf8