Browse Source

added source code

main
Inga 🏳‍🌈 3 months ago
parent
commit
afa947f907
  1. 9
      Cargo.toml
  2. 4
      input.txt
  3. 174
      src/main.rs

9
Cargo.toml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
[package]
name = "matrix_test_assignment"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
test-case = "2.1.0"

4
input.txt

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
30 1 /bin/run_me_daily
45 * /bin/run_me_hourly
* * /bin/run_me_every_minute
* 19 /bin/run_me_sixty_times

174
src/main.rs

@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
use core::fmt;
use std::{env, io::{self, BufRead}, num::ParseIntError, str, cmp::Ordering};
use test_case::test_case;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct Time {
hour: u8,
minute: u8,
}
impl str::FromStr for Time {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<_> = s.split(':').collect();
Ok(Self {
hour: parts[0].parse()?,
minute: parts[1].parse()?,
})
}
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:02}:{:02}", self.hour, self.minute)
}
}
enum NumberOrAsterisk {
Asterisk,
Number(u8),
}
impl str::FromStr for NumberOrAsterisk {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "*" {
return Ok(Self::Asterisk)
}
Ok(Self::Number(s.parse()?))
}
}
enum Schedule {
EveryMinute,
AtMinute(u8),
AtHour(u8),
AtTime(Time),
}
struct CronTask {
schedule: Schedule,
command: String,
}
impl str::FromStr for CronTask {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<_> = s.split(char::is_whitespace).filter(|&x| !x.is_empty()).collect();
let maybe_minute: NumberOrAsterisk = parts[0].parse()?;
let maybe_hour: NumberOrAsterisk = parts[1].parse()?;
let command = parts[2].to_owned();
Ok(Self {
schedule: match (maybe_hour, maybe_minute) {
(NumberOrAsterisk::Asterisk, NumberOrAsterisk::Asterisk) => Schedule::EveryMinute,
(NumberOrAsterisk::Number(hour), NumberOrAsterisk::Asterisk) => Schedule::AtHour(hour),
(NumberOrAsterisk::Asterisk, NumberOrAsterisk::Number(minute)) => Schedule::AtMinute(minute),
(NumberOrAsterisk::Number(hour), NumberOrAsterisk::Number(minute)) => Schedule::AtTime(Time { hour, minute })
},
command,
})
}
}
#[derive(Debug, PartialEq, Eq)]
enum NextRunTime {
Today(Time),
Tomorrow(Time),
}
impl fmt::Display for NextRunTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Today(time) => write!(f, "{} today", time),
Self::Tomorrow(time) => write!(f, "{} tomorrow", time),
}
}
}
struct NextRun {
time: NextRunTime,
command: String,
}
impl fmt::Display for NextRun {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} - {}", self.time, self.command)
}
}
#[test_case(Schedule::EveryMinute, "12:34".parse().unwrap() => NextRunTime::Today( "12:34".parse().unwrap()))]
#[test_case(Schedule::AtHour(11), "12:34".parse().unwrap() => NextRunTime::Tomorrow("11:00".parse().unwrap()))]
#[test_case(Schedule::AtHour(12), "12:34".parse().unwrap() => NextRunTime::Today( "12:34".parse().unwrap()))]
#[test_case(Schedule::AtHour(13), "12:34".parse().unwrap() => NextRunTime::Today( "13:00".parse().unwrap()))]
#[test_case(Schedule::AtMinute(33), "12:34".parse().unwrap() => NextRunTime::Today( "13:33".parse().unwrap()))]
#[test_case(Schedule::AtMinute(34), "12:34".parse().unwrap() => NextRunTime::Today( "12:34".parse().unwrap()))]
#[test_case(Schedule::AtMinute(35), "12:34".parse().unwrap() => NextRunTime::Today( "12:35".parse().unwrap()))]
#[test_case(Schedule::AtMinute(33), "23:34".parse().unwrap() => NextRunTime::Tomorrow("00:33".parse().unwrap()))]
#[test_case(Schedule::AtMinute(34), "23:34".parse().unwrap() => NextRunTime::Today( "23:34".parse().unwrap()))]
#[test_case(Schedule::AtMinute(35), "23:34".parse().unwrap() => NextRunTime::Today( "23:35".parse().unwrap()))]
#[test_case(Schedule::AtTime("11:33".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Tomorrow("11:33".parse().unwrap()))]
#[test_case(Schedule::AtTime("11:34".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Tomorrow("11:34".parse().unwrap()))]
#[test_case(Schedule::AtTime("11:35".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Tomorrow("11:35".parse().unwrap()))]
#[test_case(Schedule::AtTime("12:33".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Tomorrow("12:33".parse().unwrap()))]
#[test_case(Schedule::AtTime("12:34".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Today( "12:34".parse().unwrap()))]
#[test_case(Schedule::AtTime("12:35".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Today( "12:35".parse().unwrap()))]
#[test_case(Schedule::AtTime("13:33".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Today( "13:33".parse().unwrap()))]
#[test_case(Schedule::AtTime("13:34".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Today( "13:34".parse().unwrap()))]
#[test_case(Schedule::AtTime("13:35".parse().unwrap()), "12:34".parse().unwrap() => NextRunTime::Today( "13:35".parse().unwrap()))]
fn get_next_run_time(schedule: Schedule, current_time: Time) -> NextRunTime {
match schedule {
Schedule::EveryMinute => NextRunTime::Today(current_time),
Schedule::AtHour(hour) => match hour.cmp(&current_time.hour) {
Ordering::Less => NextRunTime::Tomorrow(Time { hour, minute: 0 }),
Ordering::Equal => NextRunTime::Today(current_time),
Ordering::Greater => NextRunTime::Today(Time { hour, minute: 0 }),
},
Schedule::AtMinute(minute) => match minute.cmp(&current_time.minute) {
Ordering::Less => match current_time.hour {
23 => NextRunTime::Tomorrow(Time { hour: 0, minute }),
_ => NextRunTime::Today(Time { hour: current_time.hour + 1, minute }),
},
Ordering::Equal => NextRunTime::Today(current_time),
Ordering::Greater => NextRunTime::Today(Time { hour: current_time.hour, minute } )
},
Schedule::AtTime(time) => match time.cmp(&current_time) {
Ordering::Less => NextRunTime::Tomorrow(time),
_ => NextRunTime::Today(time),
}
}
}
fn get_next_run(task: CronTask, current_time: Time) -> NextRun {
NextRun {
command: task.command,
time: get_next_run_time(task.schedule, current_time),
}
}
#[test_case("30 1 /bin/run_me_daily", "16:10".parse().unwrap() => "01:30 tomorrow - /bin/run_me_daily")]
#[test_case("45 * /bin/run_me_hourly", "16:10".parse().unwrap() => "16:45 today - /bin/run_me_hourly")]
#[test_case("* * /bin/run_me_every_minute", "16:10".parse().unwrap() => "16:10 today - /bin/run_me_every_minute")]
#[test_case("* 19 /bin/run_me_sixty_times", "16:10".parse().unwrap() => "19:00 today - /bin/run_me_sixty_times")]
#[test_case("0 0 all_zeroes", "16:10".parse().unwrap() => "00:00 tomorrow - all_zeroes")]
#[test_case("1 1 leading_zeroes", "16:10".parse().unwrap() => "01:01 tomorrow - leading_zeroes")]
#[test_case("12 12 no_zeroes", "16:10".parse().unwrap() => "12:12 tomorrow - no_zeroes")]
fn handle_line(line: &str, current_time: Time) -> String {
return format!("{}", get_next_run(line.parse().unwrap(), current_time))
}
fn main() {
let args: Vec<_> = env::args().collect();
let time = args[1].parse().unwrap();
let stdin = io::stdin();
let lines = stdin.lock().lines();
for line in lines {
println!("{}", handle_line(&line.unwrap(), time))
}
}
Loading…
Cancel
Save