Skip to content

Commit

Permalink
Sync anagram with problem-specifications (#1844)
Browse files Browse the repository at this point in the history
  • Loading branch information
senekor authored Jan 5, 2024
1 parent b2f3924 commit f03997c
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 121 deletions.
16 changes: 16 additions & 0 deletions exercises/practice/anagram/.meta/test_template.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use {{ crate_name }}::*;
use std::collections::HashSet;

{% for test in cases %}
#[test]
{% if loop.index != 1 -%}
#[ignore]
{% endif -%}
fn {{ test.description | slugify | replace(from="-", to="_") }}() {
let word = {{ test.input.subject | json_encode() }};
let inputs = &{{ test.input.candidates | json_encode() }};
let output = {{ fn_names[0] }}(word, inputs);
let expected = HashSet::from_iter({{ test.expected | json_encode() }});
assert_eq!(output, expected);
}
{% endfor -%}
83 changes: 80 additions & 3 deletions exercises/practice/anagram/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,80 @@
# 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.

[dd40c4d2-3c8b-44e5-992a-f42b393ec373]
description = "no matches"

[b3cca662-f50a-489e-ae10-ab8290a09bdc]
description = "detects two anagrams"
include = false

[03eb9bbe-8906-4ea0-84fa-ffe711b52c8b]
description = "detects two anagrams"
reimplements = "b3cca662-f50a-489e-ae10-ab8290a09bdc"

[a27558ee-9ba0-4552-96b1-ecf665b06556]
description = "does not detect anagram subsets"

[64cd4584-fc15-4781-b633-3d814c4941a4]
description = "detects anagram"

[99c91beb-838f-4ccd-b123-935139917283]
description = "detects three anagrams"

[78487770-e258-4e1f-a646-8ece10950d90]
description = "detects multiple anagrams with different case"

[1d0ab8aa-362f-49b7-9902-3d0c668d557b]
description = "does not detect non-anagrams with identical checksum"

[9e632c0b-c0b1-4804-8cc1-e295dea6d8a8]
description = "detects anagrams case-insensitively"

[b248e49f-0905-48d2-9c8d-bd02d8c3e392]
description = "detects anagrams using case-insensitive subject"

[f367325c-78ec-411c-be76-e79047f4bd54]
description = "detects anagrams using case-insensitive possible matches"

[7cc195ad-e3c7-44ee-9fd2-d3c344806a2c]
description = "does not detect an anagram if the original word is repeated"
include = false

[630abb71-a94e-4715-8395-179ec1df9f91]
description = "does not detect an anagram if the original word is repeated"
reimplements = "7cc195ad-e3c7-44ee-9fd2-d3c344806a2c"

[9878a1c9-d6ea-4235-ae51-3ea2befd6842]
description = "anagrams must use all letters exactly once"

[85757361-4535-45fd-ac0e-3810d40debc1]
description = "words are not anagrams of themselves (case-insensitive)"
include = false

[68934ed0-010b-4ef9-857a-20c9012d1ebf]
description = "words are not anagrams of themselves"
reimplements = "85757361-4535-45fd-ac0e-3810d40debc1"

[589384f3-4c8a-4e7d-9edc-51c3e5f0c90e]
description = "words are not anagrams of themselves even if letter case is partially different"
reimplements = "85757361-4535-45fd-ac0e-3810d40debc1"

[ba53e423-7e02-41ee-9ae2-71f91e6d18e6]
description = "words are not anagrams of themselves even if letter case is completely different"
reimplements = "85757361-4535-45fd-ac0e-3810d40debc1"

[a0705568-628c-4b55-9798-82e4acde51ca]
description = "words other than themselves can be anagrams"
include = false

[33d3f67e-fbb9-49d3-a90e-0beb00861da7]
description = "words other than themselves can be anagrams"
reimplements = "a0705568-628c-4b55-9798-82e4acde51ca"
218 changes: 100 additions & 118 deletions exercises/practice/anagram/tests/anagram.rs
Original file line number Diff line number Diff line change
@@ -1,186 +1,168 @@
use anagram::*;
use std::collections::HashSet;

fn process_anagram_case(word: &str, inputs: &[&str], expected: &[&str]) {
let result = anagram::anagrams_for(word, inputs);

let expected: HashSet<&str> = expected.iter().cloned().collect();

assert_eq!(result, expected);
}

#[test]
fn no_matches() {
let word = "diaper";

let inputs = ["hello", "world", "zombies", "pants"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
let inputs = &["hello", "world", "zombies", "pants"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn detect_simple_anagram() {
let word = "ant";

let inputs = ["tan", "stand", "at"];

let outputs = vec!["tan"];

process_anagram_case(word, &inputs, &outputs);
fn detects_two_anagrams() {
let word = "solemn";
let inputs = &["lemons", "cherry", "melons"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["lemons", "melons"]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn does_not_confuse_different_duplicates() {
let word = "galea";

let inputs = ["eagle"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn eliminate_anagram_subsets() {
fn does_not_detect_anagram_subsets() {
let word = "good";

let inputs = ["dog", "goody"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
let inputs = &["dog", "goody"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn detect_anagram() {
fn detects_anagram() {
let word = "listen";

let inputs = ["enlists", "google", "inlets", "banana"];

let outputs = vec!["inlets"];

process_anagram_case(word, &inputs, &outputs);
let inputs = &["enlists", "google", "inlets", "banana"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["inlets"]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn multiple_anagrams() {
fn detects_three_anagrams() {
let word = "allergy";

let inputs = [
let inputs = &[
"gallery",
"ballerina",
"regally",
"clergy",
"largely",
"leading",
];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["gallery", "regally", "largely"]);
assert_eq!(output, expected);
}

let outputs = vec!["gallery", "regally", "largely"];
#[test]
#[ignore]
fn detects_multiple_anagrams_with_different_case() {
let word = "nose";
let inputs = &["Eons", "ONES"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["Eons", "ONES"]);
assert_eq!(output, expected);
}

process_anagram_case(word, &inputs, &outputs);
#[test]
#[ignore]
fn does_not_detect_non_anagrams_with_identical_checksum() {
let word = "mass";
let inputs = &["last"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn case_insensitive_anagrams() {
fn detects_anagrams_case_insensitively() {
let word = "Orchestra";

let inputs = ["cashregister", "Carthorse", "radishes"];

let outputs = vec!["Carthorse"];

process_anagram_case(word, &inputs, &outputs);
let inputs = &["cashregister", "Carthorse", "radishes"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["Carthorse"]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn unicode_anagrams() {
let word = "ΑΒΓ";

// These words don't make sense, they're just greek letters cobbled together.
let inputs = ["ΒΓΑ", "ΒΓΔ", "γβα"];

let outputs = vec!["ΒΓΑ", "γβα"];

process_anagram_case(word, &inputs, &outputs);
fn detects_anagrams_using_case_insensitive_subject() {
let word = "Orchestra";
let inputs = &["cashregister", "carthorse", "radishes"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["carthorse"]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn misleading_unicode_anagrams() {
// Despite what a human might think these words contain different letters, the input uses Greek
// A and B while the list of potential anagrams uses Latin A and B.
let word = "ΑΒΓ";

let inputs = ["ABΓ"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
fn detects_anagrams_using_case_insensitive_possible_matches() {
let word = "orchestra";
let inputs = &["cashregister", "Carthorse", "radishes"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["Carthorse"]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn does_not_detect_a_word_as_its_own_anagram() {
let word = "banana";

let inputs = ["banana"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
fn does_not_detect_an_anagram_if_the_original_word_is_repeated() {
let word = "go";
let inputs = &["goGoGO"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn does_not_detect_a_differently_cased_word_as_its_own_anagram() {
let word = "banana";

let inputs = ["bAnana"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
fn anagrams_must_use_all_letters_exactly_once() {
let word = "tapper";
let inputs = &["patter"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn does_not_detect_a_differently_cased_unicode_word_as_its_own_anagram() {
let word = "ΑΒΓ";

let inputs = ["ΑΒγ"];

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
fn words_are_not_anagrams_of_themselves() {
let word = "BANANA";
let inputs = &["BANANA"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn same_bytes_different_chars() {
let word = "a⬂"; // 61 E2 AC 82

let inputs = ["€a"]; // E2 82 AC 61

let outputs = vec![];

process_anagram_case(word, &inputs, &outputs);
fn words_are_not_anagrams_of_themselves_even_if_letter_case_is_partially_different() {
let word = "BANANA";
let inputs = &["Banana"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

#[test]
#[ignore]
fn different_words_but_same_ascii_sum() {
let word = "bc";

let inputs = ["ad"];

let outputs = vec![];
fn words_are_not_anagrams_of_themselves_even_if_letter_case_is_completely_different() {
let word = "BANANA";
let inputs = &["banana"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter([]);
assert_eq!(output, expected);
}

process_anagram_case(word, &inputs, &outputs);
#[test]
#[ignore]
fn words_other_than_themselves_can_be_anagrams() {
let word = "LISTEN";
let inputs = &["LISTEN", "Silent"];
let output = anagrams_for(word, inputs);
let expected = HashSet::from_iter(["Silent"]);
assert_eq!(output, expected);
}

0 comments on commit f03997c

Please sign in to comment.