Skip to content

Commit 69eddaa

Browse files
authored
Merge pull request #5 from AstraBert/chore/tests
chore: add tests
2 parents 3e99271 + b44adcb commit 69eddaa

8 files changed

Lines changed: 622 additions & 2 deletions

File tree

.github/workflows/test.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- src/*.rs
7+
- Cargo.toml
8+
- jakefile.toml
9+
10+
env:
11+
CARGO_TERM_COLOR: always
12+
13+
jobs:
14+
test:
15+
name: Test on ${{ matrix.os }}
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
matrix:
19+
os: [ubuntu-latest, macos-latest]
20+
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Jake (also sets up Rust)
26+
uses: AstraBert/setup-jake@v0.1.0
27+
28+
- name: Cache cargo registry
29+
uses: actions/cache@v4
30+
with:
31+
path: |
32+
~/.cargo/registry
33+
~/.cargo/git
34+
target
35+
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
36+
restore-keys: |
37+
${{ runner.os }}-cargo-
38+
39+
- name: Run tests
40+
run: jake test

Cargo.lock

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ clap = { version = "4.6.1", features = ["derive"] }
2525
ignore = "0.4.25"
2626
serde_json = "1.0.149"
2727
tokio = { version = "1.52.1", features = ["full"] }
28+
29+
[dev-dependencies]
30+
serial_test = "3.4.0"

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ S3-backed, git-versioned object storage for agents.
1111
## Installation
1212

1313
```bash
14-
cargo install aggit@0.1.0-alpha
14+
cargo install aggit@0.2.0-alpha
1515
```
1616

17+
18+
> [!NOTE]
19+
>
20+
> `aggit` is not yet compatible with Windows.
21+
1722
### As an Agent Skill
1823

1924
You can use `aggit` as an agent skill, downloading it with the `skills` CLI tool:

jakefile.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
build = "cargo build"
2-
test = "echo 'No task yet for test'"
2+
test = "cargo test"
33
clippy-fix = "cargo clippy --fix --bin aggit --allow-dirty"
44
clippy = "cargo clippy"
55
format = "cargo fmt"

src/gitops/mod.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,3 +1127,202 @@ pub fn checkout_commit(commit_hash: String) -> anyhow::Result<()> {
11271127
restore_working_tree(commit_hash)?;
11281128
Ok(())
11291129
}
1130+
1131+
#[cfg(test)]
1132+
mod tests {
1133+
use super::*;
1134+
use std::fs;
1135+
1136+
fn setup_test_repo() {
1137+
let _ = fs::remove_dir_all(".aggit");
1138+
init(PathBuf::from(".")).unwrap();
1139+
}
1140+
1141+
fn cleanup_test_repo() {
1142+
let _ = fs::remove_dir_all(".aggit");
1143+
}
1144+
1145+
#[test]
1146+
#[serial_test::serial]
1147+
fn test_init_creates_directories() {
1148+
cleanup_test_repo();
1149+
let repo = PathBuf::from(".aggit_test_repo");
1150+
let _ = fs::remove_dir_all(&repo);
1151+
init(repo.clone()).unwrap();
1152+
assert!(repo.join(".aggit").exists());
1153+
assert!(repo.join(".aggit/objects").exists());
1154+
assert!(repo.join(".aggit/refs/heads").exists());
1155+
assert!(repo.join(".aggit/refs/index").exists());
1156+
let head = fs::read_to_string(repo.join(".aggit/HEAD")).unwrap();
1157+
assert_eq!(head, "ref: refs/heads/main");
1158+
let _ = fs::remove_dir_all(&repo);
1159+
}
1160+
1161+
#[test]
1162+
#[serial_test::serial]
1163+
fn test_hash_object_without_write() {
1164+
cleanup_test_repo();
1165+
setup_test_repo();
1166+
let mut data = b"hello world".to_vec();
1167+
let hash = hash_object(&mut data, ObjectType::Blob, false).unwrap();
1168+
assert_eq!(hash.len(), 40);
1169+
let path = PathBuf::from(".aggit/objects")
1170+
.join(&hash[..2])
1171+
.join(&hash[2..]);
1172+
assert!(!path.exists());
1173+
cleanup_test_repo();
1174+
}
1175+
1176+
#[test]
1177+
#[serial_test::serial]
1178+
fn test_hash_object_with_write() {
1179+
cleanup_test_repo();
1180+
setup_test_repo();
1181+
let mut data = b"hello world".to_vec();
1182+
let hash = hash_object(&mut data, ObjectType::Blob, true).unwrap();
1183+
let path = PathBuf::from(".aggit/objects")
1184+
.join(&hash[..2])
1185+
.join(&hash[2..]);
1186+
assert!(path.exists());
1187+
cleanup_test_repo();
1188+
}
1189+
1190+
#[test]
1191+
#[serial_test::serial]
1192+
fn test_find_object_success() {
1193+
cleanup_test_repo();
1194+
setup_test_repo();
1195+
let mut data = b"find me".to_vec();
1196+
let hash = hash_object(&mut data, ObjectType::Blob, true).unwrap();
1197+
let found = find_object(&hash).unwrap();
1198+
assert!(found.to_string_lossy().contains(&hash[..2]));
1199+
cleanup_test_repo();
1200+
}
1201+
1202+
#[test]
1203+
#[serial_test::serial]
1204+
fn test_find_object_not_found() {
1205+
cleanup_test_repo();
1206+
setup_test_repo();
1207+
let result = find_object("0000000000000000000000000000000000000000");
1208+
assert!(result.is_err());
1209+
cleanup_test_repo();
1210+
}
1211+
1212+
#[test]
1213+
fn test_read_object_roundtrip() {
1214+
let data = b"roundtrip data".to_vec();
1215+
let hash = hash_object(&mut data.clone(), ObjectType::Blob, true).unwrap();
1216+
let (obj_type, read_data) = read_object(&hash).unwrap();
1217+
assert_eq!(obj_type, ObjectType::Blob);
1218+
assert_eq!(read_data, b"roundtrip data");
1219+
}
1220+
1221+
#[test]
1222+
#[serial_test::serial]
1223+
fn test_get_current_branch() {
1224+
cleanup_test_repo();
1225+
setup_test_repo();
1226+
let branch = get_current_branch().unwrap();
1227+
assert_eq!(branch, "main");
1228+
cleanup_test_repo();
1229+
}
1230+
1231+
#[test]
1232+
fn test_index_path_for_branch() {
1233+
let path = index_path_for_branch("main");
1234+
assert_eq!(path, PathBuf::from(".aggit/refs/index/main"));
1235+
}
1236+
1237+
#[test]
1238+
fn test_head_path_for_branch() {
1239+
let path = head_path_for_branch("main");
1240+
assert_eq!(path, PathBuf::from(".aggit/refs/heads/main"));
1241+
}
1242+
1243+
#[test]
1244+
fn test_object_type_from_str() {
1245+
assert_eq!(ObjectType::from_str("blob").unwrap(), ObjectType::Blob);
1246+
assert_eq!(ObjectType::from_str("commit").unwrap(), ObjectType::Commit);
1247+
assert_eq!(ObjectType::from_str("tree").unwrap(), ObjectType::Tree);
1248+
assert!(ObjectType::from_str("unknown").is_err());
1249+
}
1250+
1251+
#[test]
1252+
fn test_cat_file_mode_from_str() {
1253+
assert!(CatFileMode::from_str("blob").is_ok());
1254+
assert!(CatFileMode::from_str("size").is_ok());
1255+
assert!(CatFileMode::from_str("type").is_ok());
1256+
assert!(CatFileMode::from_str("pretty").is_ok());
1257+
assert!(CatFileMode::from_str("invalid").is_err());
1258+
}
1259+
1260+
#[test]
1261+
#[serial_test::serial]
1262+
fn test_write_and_read_index() {
1263+
cleanup_test_repo();
1264+
setup_test_repo();
1265+
let entries = vec![IndexEntry {
1266+
ctime_s: 0,
1267+
ctime_n: 0,
1268+
mtime_s: 0,
1269+
mtime_n: 0,
1270+
dev: 0,
1271+
ino: 0,
1272+
mode: 0o100644,
1273+
uid: 0,
1274+
gid: 0,
1275+
size: 5,
1276+
sha1: [0u8; 20],
1277+
flags: 4,
1278+
path: "test.txt".to_string(),
1279+
}];
1280+
write_index(&entries).unwrap();
1281+
let read = read_index().unwrap();
1282+
assert_eq!(read.len(), 1);
1283+
assert_eq!(read[0].path, "test.txt");
1284+
cleanup_test_repo();
1285+
}
1286+
1287+
#[test]
1288+
fn test_read_tree_with_data() {
1289+
let mut tree_data = Vec::new();
1290+
tree_data.extend_from_slice(b"100644 file.txt\x00");
1291+
tree_data.extend_from_slice(&[0u8; 20]);
1292+
let entries = read_tree(None, Some(tree_data)).unwrap();
1293+
assert_eq!(entries.len(), 1);
1294+
assert_eq!(entries[0].1, "file.txt");
1295+
}
1296+
1297+
#[test]
1298+
#[serial_test::serial]
1299+
fn test_get_local_current_hash_no_commits() {
1300+
cleanup_test_repo();
1301+
setup_test_repo();
1302+
let (hash, branch) = get_local_current_hash().unwrap();
1303+
assert!(hash.is_none());
1304+
assert_eq!(branch, "main");
1305+
cleanup_test_repo();
1306+
}
1307+
1308+
#[test]
1309+
#[serial_test::serial]
1310+
fn test_list_branches_no_error() {
1311+
cleanup_test_repo();
1312+
setup_test_repo();
1313+
list_branches().unwrap();
1314+
cleanup_test_repo();
1315+
}
1316+
1317+
#[test]
1318+
#[serial_test::serial]
1319+
fn test_collect_reachable_objects_blob_only() {
1320+
cleanup_test_repo();
1321+
setup_test_repo();
1322+
let mut data = b"blob content".to_vec();
1323+
let hash = hash_object(&mut data, ObjectType::Blob, true).unwrap();
1324+
let objects = collect_reachable_objects(&hash, None).unwrap();
1325+
assert!(objects.contains(&hash));
1326+
cleanup_test_repo();
1327+
}
1328+
}

0 commit comments

Comments
 (0)