Skip to content
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

grep: sync #1965

Merged
merged 1 commit into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions exercises/practice/grep/.meta/test_template.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
use grep::*;

#[test]
#[ignore]
fn nonexistent_file_returns_error() {
let pattern = "Agamemnon";
let flags = Flags::new(&[]);
let files = ["0-1-nonexistent-file-returns-error-iliad.txt"];
assert!(grep(pattern, &flags, &files).is_err());
}

#[test]
#[ignore]
fn grep_returns_result() {
let pattern = "Agamemnon";
let flags = Flags::new(&[]);
let files = Files::new(&["0-2-grep-returns-result-iliad.txt"]);
assert!(grep(pattern, &flags, files.as_ref()).is_ok());
}

{% for test_group in cases %}
{% set group_idx = loop.index %}
{% for test in test_group.cases %}
{% set test_idx = loop.index %}

{#
This prefix is added to the file names to ensure each test case has its own
set of files. This is necessary because every test case creates and deletes
its own files, so the names must be unique to prevent conflicts.
#}
{% set prefix = group_idx ~ "-" ~ test_idx %}

#[test]
#[ignore]
fn {{ test.description | snake_case }}() {
let pattern = {{ test.input.pattern | json_encode() }};
let flags = Flags::new(&{{ test.input.flags | json_encode() }});
let files = Files::new(&[
{% for file in test.input.files -%}
"{{ prefix }}-{{ file }}",
{%- endfor %}
]);
let actual = grep(pattern, &flags, files.as_ref()).unwrap();
let expected: &[&str] = &[
{% if test.input.files | length > 1 or test.input.flags is containing("-l") %}
{% for line in test.expected %}
"{{ prefix }}-{{ line }}",
{% endfor %}
{% else %}
{% for line in test.expected %}
"{{ line }}",
{% endfor %}
{% endif %}
];
assert_eq!(actual, expected);
}
{% endfor %}
{% endfor %}

static ILIAD_CONTENT: &str = "\
Achilles sing, O Goddess! Peleus' son;
His wrath pernicious, who ten thousand woes
Caused to Achaia's host, sent many a soul
Illustrious into Ades premature,
And Heroes gave (so stood the will of Jove)
To dogs and to all ravening fowls a prey,
When fierce dispute had separated once
The noble Chief Achilles from the son
Of Atreus, Agamemnon, King of men.
";

static MIDSUMMER_NIGHT_CONTENT: &str = "\
I do entreat your grace to pardon me.
I know not by what power I am made bold,
Nor how it may concern my modesty,
In such a presence here to plead my thoughts;
But I beseech your grace that I may know
The worst that may befall me in this case,
If I refuse to wed Demetrius.
";

static PARADISE_LOST_CONTENT: &str = "\
Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
Sing Heav'nly Muse, that on the secret top
Of Oreb, or of Sinai, didst inspire
That Shepherd, who first taught the chosen Seed
";

/// In The White Night
/// A poem by Alexander Blok(https://en.wikipedia.org/wiki/Alexander_Blok)
/// a Russian poet who is regarded as one of the most important figures of the Silver Age of Russian Poetry
/// You can read the translation here: https://lyricstranslate.com/ru/белой-ночью-месяц-красный-white-night-crimson-crescent.html
static IN_THE_WHITE_NIGHT_CONTENT: &str = "
Белой ночью месяц красный
Выплывает в синеве.
Бродит призрачно-прекрасный,
Отражается в Неве.
Мне провидится и снится
Исполненье тайных дум.
В вас ли доброе таится,
Красный месяц, тихий шум?..
";

struct Files<'a> {
file_names: &'a [&'a str],
}

impl<'a> Files<'a> {
fn new(file_names: &'a [&'a str]) -> Self {
for file_name in file_names {
let content = if file_name.ends_with("iliad.txt") {
ILIAD_CONTENT
} else if file_name.ends_with("midsummer-night.txt") {
MIDSUMMER_NIGHT_CONTENT
} else if file_name.ends_with("paradise-lost.txt") {
PARADISE_LOST_CONTENT
} else {
IN_THE_WHITE_NIGHT_CONTENT
};
std::fs::write(file_name, content).unwrap_or_else(|_| {
panic!(
"Error setting up file '{file_name}' with the following content:\n{content}"
)
});
}

Self { file_names }
}
}

impl<'a> Drop for Files<'a> {
fn drop(&mut self) {
for file_name in self.file_names {
std::fs::remove_file(file_name)
.unwrap_or_else(|e| panic!("Could not delete file '{file_name}': {e}"));
}
}
}

impl<'a> AsRef<[&'a str]> for Files<'a> {
fn as_ref(&self) -> &[&'a str] {
self.file_names
}
}
88 changes: 85 additions & 3 deletions exercises/practice/grep/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,85 @@
# 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.

[9049fdfd-53a7-4480-a390-375203837d09]
description = "Test grepping a single file -> One file, one match, no flags"

[76519cce-98e3-46cd-b287-aac31b1d77d6]
description = "Test grepping a single file -> One file, one match, print line numbers flag"

[af0b6d3c-e0e8-475e-a112-c0fc10a1eb30]
description = "Test grepping a single file -> One file, one match, case-insensitive flag"

[ff7af839-d1b8-4856-a53e-99283579b672]
description = "Test grepping a single file -> One file, one match, print file names flag"

[8625238a-720c-4a16-81f2-924ec8e222cb]
description = "Test grepping a single file -> One file, one match, match entire lines flag"

[2a6266b3-a60f-475c-a5f5-f5008a717d3e]
description = "Test grepping a single file -> One file, one match, multiple flags"

[842222da-32e8-4646-89df-0d38220f77a1]
description = "Test grepping a single file -> One file, several matches, no flags"

[4d84f45f-a1d8-4c2e-a00e-0b292233828c]
description = "Test grepping a single file -> One file, several matches, print line numbers flag"

[0a483b66-315b-45f5-bc85-3ce353a22539]
description = "Test grepping a single file -> One file, several matches, match entire lines flag"

[3d2ca86a-edd7-494c-8938-8eeed1c61cfa]
description = "Test grepping a single file -> One file, several matches, case-insensitive flag"

[1f52001f-f224-4521-9456-11120cad4432]
description = "Test grepping a single file -> One file, several matches, inverted flag"

[7a6ede7f-7dd5-4364-8bf8-0697c53a09fe]
description = "Test grepping a single file -> One file, no matches, various flags"

[3d3dfc23-8f2a-4e34-abd6-7b7d140291dc]
description = "Test grepping a single file -> One file, one match, file flag takes precedence over line flag"

[87b21b24-b788-4d6e-a68b-7afe9ca141fe]
description = "Test grepping a single file -> One file, several matches, inverted and match entire lines flags"

[ba496a23-6149-41c6-a027-28064ed533e5]
description = "Test grepping multiples files at once -> Multiple files, one match, no flags"

[4539bd36-6daa-4bc3-8e45-051f69f5aa95]
description = "Test grepping multiples files at once -> Multiple files, several matches, no flags"

[9fb4cc67-78e2-4761-8e6b-a4b57aba1938]
description = "Test grepping multiples files at once -> Multiple files, several matches, print line numbers flag"

[aeee1ef3-93c7-4cd5-af10-876f8c9ccc73]
description = "Test grepping multiples files at once -> Multiple files, one match, print file names flag"

[d69f3606-7d15-4ddf-89ae-01df198e6b6c]
description = "Test grepping multiples files at once -> Multiple files, several matches, case-insensitive flag"

[82ef739d-6701-4086-b911-007d1a3deb21]
description = "Test grepping multiples files at once -> Multiple files, several matches, inverted flag"

[77b2eb07-2921-4ea0-8971-7636b44f5d29]
description = "Test grepping multiples files at once -> Multiple files, one match, match entire lines flag"

[e53a2842-55bb-4078-9bb5-04ac38929989]
description = "Test grepping multiples files at once -> Multiple files, one match, multiple flags"

[9c4f7f9a-a555-4e32-bb06-4b8f8869b2cb]
description = "Test grepping multiples files at once -> Multiple files, no matches, various flags"

[ba5a540d-bffd-481b-bd0c-d9a30f225e01]
description = "Test grepping multiples files at once -> Multiple files, several matches, file flag takes precedence over line number flag"

[ff406330-2f0b-4b17-9ee4-4b71c31dd6d2]
description = "Test grepping multiples files at once -> Multiple files, several matches, inverted and match entire lines flags"
Loading