use zagan_bet::version::{ VERSION, Version, compatible, hello_line, is_newer, parse_hello, parse_pong, pong_line, unix_time_ms, }; #[test] fn versions_parse_and_reject_nonsense() { assert_eq!( Version::parse("4.0.0"), Some(Version { major: 4, minor: 0, patch: 0 }) ); assert_eq!( Version::parse("v4.1.2"), Some(Version { major: 4, minor: 1, patch: 2 }) ); assert_eq!( Version::parse("4.0.0-rc1").map(|v| (v.major, v.minor, v.patch)), Some((4, 0, 0)) ); assert_eq!(Version::parse("4.0.0+build7").map(|v| v.patch), Some(0)); for bad in ["", "4", "4.0", "4.0.0.1", "x.0.0", "4.x.0", "4.0.0-"] { assert!(Version::parse(bad).is_none(), "{bad:?} should not parse"); } assert!( Version::parse(VERSION).is_some(), "the build version must parse" ); } #[test] fn compatibility_is_major_and_minor_only() { assert!(compatible("4.0.0", "4.0.9")); assert!(compatible("4.2.7", "4.2.1")); assert!(!compatible("4.0.0", "4.1.0")); assert!(!compatible("4.0.0", "5.0.0")); assert!(!compatible("nope", "4.0.0")); } #[test] fn newer_versions_are_ordered_by_major_minor_patch() { assert!(is_newer("4.0.1", "4.0.0")); assert!(is_newer("4.1.0", "4.0.9")); assert!(is_newer("5.0.0", "4.9.9")); assert!(!is_newer("4.0.0", "4.0.0")); assert!(!is_newer("4.0.0", "4.0.1")); assert!(!is_newer("nonsense", "4.0.0")); } #[test] fn the_hello_reply_round_trips() { let line = hello_line( "4.0.0", "4.1.2", "https://zagan.example/", 1_700_000_000_123, ); let reply = parse_hello(&line).expect("parse a generated reply"); assert_eq!(reply.version, "4.0.0"); assert_eq!(reply.latest, "4.1.2"); assert_eq!(reply.url, "https://zagan.example/"); assert_eq!(reply.time, 1_700_000_000_123); assert!( parse_hello("HELLO 4.0.0 url=https://x/ time=1").is_none(), "latest is required" ); assert!( parse_hello("HELLO 4.0.0 latest=4.0.0 time=1").is_none(), "url is required" ); assert!( parse_hello("HELLO 4.0.0 latest=4.0.0 url=https://x/").is_none(), "time is required" ); assert!(parse_hello("PONG").is_none()); assert!(parse_hello("HELLO").is_none()); } #[test] fn pong_carries_the_server_time() { let line = pong_line(1_700_000_000_456); assert_eq!(line, "PONG 1700000000456"); assert_eq!(parse_pong(&line), Some(1_700_000_000_456)); assert!(parse_pong("PONG").is_none()); assert!(parse_pong("RES 1 PONG 1700000000456").is_none()); assert!(unix_time_ms() > 1_600_000_000_000); } /// The GUI is a client, so it must ship in lockstep with the TUI and server. /// Keep `gui/Cargo.toml` at the same version as the root package. #[test] fn the_gui_member_uses_the_same_version() { let gui_manifest = include_str!("../gui/Cargo.toml"); let gui_version = gui_manifest .lines() .find_map(|line| line.trim().strip_prefix("version = ")) .expect("gui/Cargo.toml declares a version") .trim_matches('"'); assert_eq!(gui_version, VERSION); } /// The gateway is a frontend too; keep it in lockstep with the core. #[test] fn the_webd_member_uses_the_same_version() { let manifest = include_str!("../webd/Cargo.toml"); let version = manifest .lines() .find_map(|line| line.trim().strip_prefix("version = ")) .expect("webd/Cargo.toml declares a version") .trim_matches('"'); assert_eq!(version, VERSION); } /// egui's dependency tree must never enter the TUI or server build graph. /// The GUI is a workspace member that depends on this package, never the /// other way round. #[test] fn the_root_package_does_not_depend_on_the_gui() { let manifest = include_str!("../Cargo.toml"); for forbidden in ["eframe", "egui"] { assert!( !manifest.contains(forbidden), "the root package must not depend on {forbidden}" ); } }