Skip to content

Commit

Permalink
add codecov (#2)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexandre Hanot <>
  • Loading branch information
Almaju authored Oct 10, 2023
1 parent 30318d1 commit d992cf7
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 108 deletions.
19 changes: 18 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
on: [push, pull_request]
on:
push:
branches: [ main ]
pull_request:

name: Continuous integration

Expand Down Expand Up @@ -62,3 +65,17 @@ jobs:
with:
command: clippy
args: -- -D warnings

coverage:
name: Code Coverage
runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov -p todolist --fail-uncovered-lines 0
3 changes: 0 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions domain/todolist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,3 @@ version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1", features = ["derive"] }
101 changes: 4 additions & 97 deletions domain/todolist/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use serde::{Deserialize, Serialize};

#[derive(Default, Serialize, Deserialize)]
#[derive(Default)]
pub struct TodoList {
pub tasks: Vec<Task>,
}

#[derive(Serialize, Deserialize)]
pub struct Task {
pub description: String,
pub done: bool,
Expand All @@ -17,9 +14,10 @@ pub enum Command {
}

#[derive(Debug)]
pub enum Error {}
pub enum Error {
TaskNotFound,
}

#[derive(Serialize, Deserialize)]
pub enum Event {
TaskAdded { description: String },
TaskCompleted { index: usize },
Expand Down Expand Up @@ -50,94 +48,3 @@ impl TodoList {
self
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_add_task() {
let mut todo_list = TodoList::default();
let cmd = Command::AddTask {
description: "Test task".to_string(),
};
let events = todo_list.handle(cmd).unwrap();
todo_list.apply(events);

assert_eq!(todo_list.tasks.len(), 1);
assert_eq!(todo_list.tasks[0].description, "Test task");
assert_eq!(todo_list.tasks[0].done, false);
}

#[test]
fn test_complete_task() {
let mut todo_list = TodoList::default();
let cmd_add = Command::AddTask {
description: "Test task".to_string(),
};
let events_add = todo_list.handle(cmd_add).unwrap();
todo_list.apply(events_add);

let cmd_complete = Command::CompleteTask { index: 0 };
let events_complete = todo_list.handle(cmd_complete).unwrap();
todo_list.apply(events_complete);

assert_eq!(todo_list.tasks.len(), 1);
assert_eq!(todo_list.tasks[0].done, true);
}

#[test]
fn test_handle() {
let todo_list = TodoList::default();

// Testing AddTask command
match todo_list.handle(Command::AddTask {
description: "Test task".to_string(),
}) {
Ok(events) => {
assert_eq!(events.len(), 1);
if let Event::TaskAdded { description } = &events[0] {
assert_eq!(description, "Test task");
} else {
panic!("Expected TaskAdded event");
}
}
Err(_) => panic!("Expected Ok, got Err"),
}

// Testing CompleteTask command
match todo_list.handle(Command::CompleteTask { index: 0 }) {
Ok(events) => {
assert_eq!(events.len(), 1);
if let Event::TaskCompleted { index } = &events[0] {
assert_eq!(*index, 0);
} else {
panic!("Expected TaskCompleted event");
}
}
Err(_) => panic!("Expected Ok, got Err"),
}
}

#[test]
fn test_apply() {
let mut todo_list = TodoList::default();

let events = vec![
Event::TaskAdded {
description: "Task 1".to_string(),
},
Event::TaskAdded {
description: "Task 2".to_string(),
},
Event::TaskCompleted { index: 0 },
];
todo_list.apply(events);

assert_eq!(todo_list.tasks.len(), 2);
assert_eq!(todo_list.tasks[0].description, "Task 1");
assert_eq!(todo_list.tasks[0].done, true);
assert_eq!(todo_list.tasks[1].description, "Task 2");
assert_eq!(todo_list.tasks[1].done, false);
}
}
94 changes: 94 additions & 0 deletions domain/todolist/tests/todolist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use todolist::*;

#[test]
fn test_add_task() {
let mut todo_list = TodoList::default();
let cmd = Command::AddTask {
description: "Test task".to_string(),
};
let events = todo_list.handle(cmd).unwrap();
todo_list.apply(events);

assert_eq!(todo_list.tasks.len(), 1);
assert_eq!(todo_list.tasks[0].description, "Test task");
assert_eq!(todo_list.tasks[0].done, false);
}

#[test]
fn test_complete_task() {
let mut todo_list = TodoList::default();
let cmd_add = Command::AddTask {
description: "Test task".to_string(),
};
let events_add = todo_list.handle(cmd_add).unwrap();
todo_list.apply(events_add);

let cmd_complete = Command::CompleteTask { index: 0 };
let events_complete = todo_list.handle(cmd_complete).unwrap();
todo_list.apply(events_complete);

assert_eq!(todo_list.tasks.len(), 1);
assert_eq!(todo_list.tasks[0].done, true);
}

#[test]
fn test_handle() {
let todo_list = TodoList::default();

// Testing AddTask command
match todo_list.handle(Command::AddTask {
description: "Test task".to_string(),
}) {
Ok(events) => {
assert_eq!(events.len(), 1);
if let Event::TaskAdded { description } = &events[0] {
assert_eq!(description, "Test task");
} else {
panic!("Expected TaskAdded event");
}
}
Err(_) => panic!("Expected Ok, got Err"),
}

// Testing CompleteTask command
match todo_list.handle(Command::CompleteTask { index: 0 }) {
Ok(events) => {
assert_eq!(events.len(), 1);
if let Event::TaskCompleted { index } = &events[0] {
assert_eq!(*index, 0);
} else {
panic!("Expected TaskCompleted event");
}
}
Err(_) => panic!("Expected Ok, got Err"),
}
}

#[test]
fn test_apply() {
let mut todo_list = TodoList::default();

let events = vec![
Event::TaskAdded {
description: "Task 1".to_string(),
},
Event::TaskAdded {
description: "Task 2".to_string(),
},
Event::TaskCompleted { index: 0 },
];
todo_list.apply(events);

assert_eq!(todo_list.tasks.len(), 2);
assert_eq!(todo_list.tasks[0].description, "Task 1");
assert_eq!(todo_list.tasks[0].done, true);
assert_eq!(todo_list.tasks[1].description, "Task 2");
assert_eq!(todo_list.tasks[1].done, false);
}

#[test]
fn test_debug_error() {
let error = Error::TaskNotFound;

assert_eq!(format!("{:?}", error), "TaskNotFound");
}
33 changes: 29 additions & 4 deletions infrastructure/local-storage/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use application::services::TodoListStore;
use application::todolist::{Event, TodoList};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use web_sys::Storage;

fn get_local_storage() -> Storage {
Expand All @@ -19,12 +20,12 @@ impl TodoListStore for TodoListLocalStorage {
.get_item("todolist")
.unwrap()
.map(|json| {
let events: Vec<Event> = serde_json::from_str(&json).unwrap();
let events: Vec<EventDTO> = serde_json::from_str(&json).unwrap();
events
})
.unwrap_or_default();
let mut todolist = TodoList::default();
todolist.apply(events);
todolist.apply(events.into_iter().map(|e| e.into()).collect());
todolist
}

Expand All @@ -34,12 +35,36 @@ impl TodoListStore for TodoListLocalStorage {
.get_item("todolist")
.unwrap()
.map(|json| {
let events: Vec<Event> = serde_json::from_str(&json).unwrap();
let events: Vec<EventDTO> = serde_json::from_str(&json).unwrap();
events
})
.unwrap_or_default();
events.extend(new_events);
events.extend(new_events.into_iter().map(|e| e.into()));
let json = serde_json::to_string(&events).unwrap();
storage.set_item("todolist", &json).unwrap();
}
}

#[derive(Serialize, Deserialize)]
enum EventDTO {
TaskAdded { description: String },
TaskCompleted { index: usize },
}

impl From<Event> for EventDTO {
fn from(event: Event) -> Self {
match event {
Event::TaskAdded { description } => EventDTO::TaskAdded { description },
Event::TaskCompleted { index } => EventDTO::TaskCompleted { index },
}
}
}

impl From<EventDTO> for Event {
fn from(dto: EventDTO) -> Self {
match dto {
EventDTO::TaskAdded { description } => Event::TaskAdded { description },
EventDTO::TaskCompleted { index } => Event::TaskCompleted { index },
}
}
}
41 changes: 41 additions & 0 deletions sort_derive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os
import fileinput
import re

a = re.compile(r"^#\[derive\((\s*[a-zA-Z0-9_]+\s*,)*(\s*[a-zA-Z0-9_]+\s*)\)]$")

special = [
"Copy",
"Clone",
"Default",
"Debug",
"PartialEq",
"Eq",
"PartialOrd",
"Ord",
"Serialize",
"Deserialize",
]

special = {x: i for i, x in enumerate(special)}

for root, dirs, files in os.walk("."):
if "target" in root:
continue
for name in files:
path = root + os.sep + name

if name.endswith(".rs"):
print(path)
for line in fileinput.input(path, inplace=True):
if a.match(line):
derives = line[9:-3]
derives = [
(special.get(x.strip(), 100), x.strip())
for x in derives.split(",")
]
derives.sort()
line = "#[derive(" + ", ".join(x[1] for x in derives) + ")]"
print(line)
else:
print(line, end="")

0 comments on commit d992cf7

Please sign in to comment.