domain_encode_non_serde.rs (44910B)
1 #[path = "../src/test_fixtures.rs"] 2 mod test_fixtures; 3 4 use std::str::FromStr; 5 6 use radroots_core::{Currency, Decimal, Money, Quantity, QuantityPrice, Unit}; 7 use radroots_event::{ 8 farm::change_set::{GcsLocation, GeoJsonPoint, GeoJsonPolygon}, 9 farm::coop::{Coop, CoopLocation, CoopRef}, 10 farm::plot::{Plot, PlotLocation, PlotRef}, 11 farm::resource_area::{ResourceArea, ResourceAreaLocation, ResourceAreaRef}, 12 farm::resource_cap::{ResourceHarvestCap, ResourceHarvestProduct}, 13 farm::{Farm, FarmPublicLocation, FarmRef}, 14 id::{DTag, InventoryBinId}, 15 listing::operational::{ 16 OperationalListing, OperationalListingAvailability, OperationalListingBin, 17 OperationalListingDeliveryMethod, OperationalListingProduct, 18 OperationalListingPublicLocation, 19 }, 20 post::document::{Document, DocumentSubject}, 21 }; 22 use radroots_event_codec::encode::EventEncodeError; 23 use radroots_event_codec::encode::coop::{coop_build_tags, coop_ref_tags}; 24 use radroots_event_codec::encode::coop::{coop_members_farms_list_set, coop_members_list_set}; 25 use radroots_event_codec::encode::document::document_build_tags; 26 use radroots_event_codec::encode::farm::{farm_build_tags, farm_ref_tags}; 27 use radroots_event_codec::encode::farm::{ 28 farm_members_list_set, farm_operational_listings_list_set, 29 }; 30 use radroots_event_codec::encode::operational_listing::operational_listing_build_tags; 31 use radroots_event_codec::encode::operational_listing::{ 32 OperationalListingTagOptions, operational_listing_tags_full, 33 operational_listing_tags_with_options, 34 }; 35 use radroots_event_codec::encode::plot::{plot_address, plot_build_tags}; 36 use radroots_event_codec::encode::resource_area::{ 37 resource_area_build_tags, resource_area_ref_tags, 38 }; 39 use radroots_event_codec::encode::resource_area::{ 40 resource_area_members_farms_list_set, resource_area_members_plots_list_set, 41 resource_area_stewards_list_set, 42 }; 43 use radroots_event_codec::encode::resource_cap::resource_harvest_cap_build_tags; 44 use test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; 45 46 const VALID_PUBKEY: &str = FIXTURE_ALICE_PUBLIC_KEY_HEX; 47 const VALID_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; 48 const VALID_PLOT_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAQ"; 49 const VALID_COOP_D_TAG: &str = "BAAAAAAAAAAAAAAAAAAAAA"; 50 const VALID_AREA_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAw"; 51 const VALID_CAP_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAABA"; 52 const VALID_DOC_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAg"; 53 54 fn decimal(value: &str) -> Decimal { 55 Decimal::from_str(value).expect("valid decimal") 56 } 57 58 fn money(amount: Decimal, currency: Currency) -> Money { 59 Money::try_new(amount, currency).unwrap() 60 } 61 62 fn quantity(amount: Decimal, unit: Unit) -> Quantity { 63 Quantity::try_new(amount, unit).unwrap() 64 } 65 66 fn quantity_price(amount: Money, quantity: Quantity) -> QuantityPrice { 67 QuantityPrice::try_new(amount, quantity).unwrap() 68 } 69 70 fn listing_d_tag(raw: &str) -> DTag { 71 raw.parse().unwrap() 72 } 73 74 fn bin_id(raw: &str) -> InventoryBinId { 75 raw.parse().unwrap() 76 } 77 78 fn sample_gcs(geohash: &str) -> GcsLocation { 79 GcsLocation { 80 lat: 37.0, 81 lng: -122.0, 82 geohash: geohash.to_string(), 83 point: GeoJsonPoint { 84 r#type: "Point".to_string(), 85 coordinates: [-122.0, 37.0], 86 }, 87 polygon: GeoJsonPolygon { 88 r#type: "Polygon".to_string(), 89 coordinates: vec![vec![ 90 [-122.0, 37.0], 91 [-122.0, 37.0001], 92 [-122.0001, 37.0001], 93 [-122.0, 37.0], 94 ]], 95 }, 96 accuracy: None, 97 altitude: None, 98 tag_0: None, 99 label: None, 100 area: None, 101 elevation: None, 102 soil: None, 103 climate: None, 104 gc_id: None, 105 gc_name: None, 106 gc_admin1_id: None, 107 gc_admin1_name: None, 108 gc_country_id: None, 109 gc_country_name: None, 110 } 111 } 112 113 fn sample_coop() -> Coop { 114 Coop { 115 d_tag: VALID_COOP_D_TAG.to_string(), 116 name: "Test Coop".to_string(), 117 about: None, 118 website: None, 119 picture: None, 120 banner: None, 121 location: Some(CoopLocation { 122 primary: None, 123 city: None, 124 region: None, 125 country: None, 126 gcs: sample_gcs("9q8yy"), 127 }), 128 tags: Some(vec!["regional".to_string()]), 129 } 130 } 131 132 fn sample_farm() -> Farm { 133 Farm { 134 d_tag: VALID_FARM_D_TAG.to_string(), 135 name: "Test Farm".to_string(), 136 about: None, 137 website: None, 138 picture: None, 139 banner: None, 140 location: Some(FarmPublicLocation { 141 primary: "Test Farm".to_string(), 142 city: Some("Santa Cruz".to_string()), 143 region: Some("California".to_string()), 144 country: Some("US".to_string()), 145 geohash: "9q8yy".to_string(), 146 }), 147 tags: Some(vec!["orchard".to_string()]), 148 } 149 } 150 151 fn sample_plot() -> Plot { 152 Plot { 153 d_tag: VALID_PLOT_D_TAG.to_string(), 154 farm: FarmRef { 155 pubkey: VALID_PUBKEY.to_string(), 156 d_tag: VALID_FARM_D_TAG.to_string(), 157 }, 158 name: "Plot 1".to_string(), 159 about: None, 160 location: Some(PlotLocation { 161 primary: None, 162 city: None, 163 region: None, 164 country: None, 165 gcs: sample_gcs("9q8yy"), 166 }), 167 tags: Some(vec!["orchard".to_string()]), 168 } 169 } 170 171 fn sample_listing() -> OperationalListing { 172 let quantity = quantity(Decimal::from(1u32), Unit::Each); 173 let price_per_canonical_unit = 174 quantity_price(money(Decimal::from(10u32), Currency::USD), quantity.clone()); 175 176 OperationalListing { 177 d_tag: listing_d_tag(VALID_DOC_D_TAG), 178 published_at: None, 179 farm: FarmRef { 180 pubkey: VALID_PUBKEY.to_string(), 181 d_tag: VALID_FARM_D_TAG.to_string(), 182 }, 183 product: OperationalListingProduct { 184 key: "nutmeg".to_string(), 185 title: "Nutmeg".to_string(), 186 category: "spice".to_string(), 187 summary: None, 188 process: None, 189 lot: None, 190 location: None, 191 profile: None, 192 year: None, 193 }, 194 primary_bin_id: bin_id("bin-1"), 195 bins: vec![OperationalListingBin { 196 bin_id: bin_id("bin-1"), 197 quantity, 198 price_per_canonical_unit, 199 display_amount: None, 200 display_unit: None, 201 display_label: None, 202 display_price: None, 203 display_price_unit: None, 204 }], 205 resource_area: None, 206 plot: None, 207 discounts: None, 208 inventory_available: Some(decimal("12")), 209 availability: Some(OperationalListingAvailability::Window { 210 start: Some(1), 211 end: Some(2), 212 }), 213 delivery_method: Some(OperationalListingDeliveryMethod::Shipping), 214 location: None, 215 images: None, 216 } 217 } 218 219 fn sample_resource_area() -> ResourceArea { 220 ResourceArea { 221 d_tag: VALID_AREA_D_TAG.to_string(), 222 name: "Banda Grove".to_string(), 223 about: None, 224 location: ResourceAreaLocation { 225 primary: None, 226 city: None, 227 region: None, 228 country: None, 229 gcs: sample_gcs("pmb5v"), 230 }, 231 tags: Some(vec!["nutmeg".to_string()]), 232 } 233 } 234 235 fn sample_resource_cap() -> ResourceHarvestCap { 236 ResourceHarvestCap { 237 d_tag: VALID_CAP_D_TAG.to_string(), 238 resource_area: ResourceAreaRef { 239 pubkey: VALID_PUBKEY.to_string(), 240 d_tag: VALID_AREA_D_TAG.to_string(), 241 }, 242 product: ResourceHarvestProduct { 243 key: "nutmeg".to_string(), 244 category: Some("spice".to_string()), 245 }, 246 start: 1, 247 end: 2, 248 cap_quantity: quantity(decimal("1000"), Unit::MassG), 249 display_amount: None, 250 display_unit: None, 251 display_label: None, 252 tags: None, 253 } 254 } 255 256 fn sample_document() -> Document { 257 Document { 258 d_tag: VALID_DOC_D_TAG.to_string(), 259 doc_type: "charter".to_string(), 260 title: "Charter".to_string(), 261 version: "1.0.0".to_string(), 262 summary: None, 263 effective_at: None, 264 body_markdown: None, 265 subject: DocumentSubject { 266 pubkey: VALID_PUBKEY.to_string(), 267 address: Some(format!("30340:{VALID_PUBKEY}:{VALID_FARM_D_TAG}")), 268 }, 269 tags: Some(vec!["policy".to_string()]), 270 } 271 } 272 273 #[test] 274 fn coop_encode_and_list_set_paths() { 275 let tags = coop_build_tags(&sample_coop()).expect("coop tags"); 276 assert!( 277 tags.iter() 278 .any(|tag| tag.first().map(|v| v.as_str()) == Some("d")) 279 ); 280 assert!( 281 tags.iter() 282 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 283 ); 284 assert!( 285 tags.iter() 286 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 287 ); 288 289 let mut coop = sample_coop(); 290 coop.tags = None; 291 coop.location = None; 292 let tags = coop_build_tags(&coop).expect("coop tags without optional fields"); 293 assert!( 294 !tags 295 .iter() 296 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 297 ); 298 assert!( 299 !tags 300 .iter() 301 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 302 ); 303 304 let mut coop = sample_coop(); 305 coop.d_tag = " ".to_string(); 306 let err = coop_build_tags(&coop).expect_err("empty d_tag"); 307 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 308 309 let mut coop = sample_coop(); 310 coop.name = " ".to_string(); 311 let err = coop_build_tags(&coop).expect_err("empty name"); 312 assert!(matches!(err, EventEncodeError::EmptyRequiredField("name"))); 313 314 let mut coop = sample_coop(); 315 coop.location.as_mut().expect("location").gcs.geohash = " ".to_string(); 316 let err = coop_build_tags(&coop).expect_err("empty geohash"); 317 assert!(matches!( 318 err, 319 EventEncodeError::EmptyRequiredField("location.gcs.geohash") 320 )); 321 322 let mut coop = sample_coop(); 323 coop.d_tag = "invalid".to_string(); 324 let err = coop_build_tags(&coop).expect_err("invalid d_tag"); 325 assert!(matches!(err, EventEncodeError::InvalidField("d_tag"))); 326 327 let tags = coop_ref_tags(&CoopRef { 328 pubkey: VALID_PUBKEY.to_string(), 329 d_tag: VALID_COOP_D_TAG.to_string(), 330 }) 331 .expect("coop ref tags"); 332 assert_eq!(tags.len(), 2); 333 334 let err = coop_ref_tags(&CoopRef { 335 pubkey: " ".to_string(), 336 d_tag: VALID_COOP_D_TAG.to_string(), 337 }) 338 .expect_err("empty coop pubkey"); 339 assert!(matches!( 340 err, 341 EventEncodeError::EmptyRequiredField("coop.pubkey") 342 )); 343 344 let err = coop_ref_tags(&CoopRef { 345 pubkey: VALID_PUBKEY.to_string(), 346 d_tag: " ".to_string(), 347 }) 348 .expect_err("empty coop d_tag"); 349 assert!(matches!( 350 err, 351 EventEncodeError::EmptyRequiredField("coop.d_tag") 352 )); 353 354 let err = coop_ref_tags(&CoopRef { 355 pubkey: VALID_PUBKEY.to_string(), 356 d_tag: "invalid".to_string(), 357 }) 358 .expect_err("invalid coop d_tag"); 359 assert!(matches!(err, EventEncodeError::InvalidField("coop.d_tag"))); 360 361 let err = coop_members_list_set("invalid", ["member"]).expect_err("invalid coop id"); 362 assert!(matches!(err, EventEncodeError::InvalidField("coop_id"))); 363 364 let err = coop_members_list_set(" ", ["member"]).expect_err("empty coop id"); 365 assert!(matches!( 366 err, 367 EventEncodeError::EmptyRequiredField("coop_id") 368 )); 369 370 let members = coop_members_list_set(VALID_COOP_D_TAG, ["member"]).expect("members list set"); 371 assert_eq!(members.entries.len(), 1); 372 assert_eq!(members.entries[0].tag, "p"); 373 374 let err = coop_members_list_set(VALID_COOP_D_TAG, [" "]).expect_err("empty member entry"); 375 assert!(matches!( 376 err, 377 EventEncodeError::EmptyRequiredField("entry.values") 378 )); 379 380 let member_farms = coop_members_farms_list_set( 381 VALID_COOP_D_TAG, 382 vec![FarmRef { 383 pubkey: VALID_PUBKEY.to_string(), 384 d_tag: VALID_FARM_D_TAG.to_string(), 385 }], 386 ) 387 .expect("member farms list set"); 388 assert_eq!(member_farms.entries.len(), 2); 389 assert_eq!(member_farms.entries[0].tag, "a"); 390 assert_eq!(member_farms.entries[1].tag, "p"); 391 392 let member_farms_from_array = coop_members_farms_list_set( 393 VALID_COOP_D_TAG, 394 [FarmRef { 395 pubkey: VALID_PUBKEY.to_string(), 396 d_tag: VALID_FARM_D_TAG.to_string(), 397 }], 398 ) 399 .expect("member farms list set array"); 400 assert_eq!(member_farms_from_array.entries.len(), 2); 401 assert_eq!(member_farms_from_array.entries[0].tag, "a"); 402 assert_eq!(member_farms_from_array.entries[1].tag, "p"); 403 404 let err = coop_members_farms_list_set( 405 VALID_COOP_D_TAG, 406 vec![FarmRef { 407 pubkey: " ".to_string(), 408 d_tag: VALID_FARM_D_TAG.to_string(), 409 }], 410 ) 411 .expect_err("empty farm pubkey"); 412 assert!(matches!( 413 err, 414 EventEncodeError::EmptyRequiredField("farm.pubkey") 415 )); 416 417 let err = coop_members_farms_list_set( 418 VALID_COOP_D_TAG, 419 vec![FarmRef { 420 pubkey: VALID_PUBKEY.to_string(), 421 d_tag: " ".to_string(), 422 }], 423 ) 424 .expect_err("empty farm d_tag"); 425 assert!(matches!( 426 err, 427 EventEncodeError::EmptyRequiredField("farm.d_tag") 428 )); 429 430 let err = coop_members_farms_list_set( 431 VALID_COOP_D_TAG, 432 vec![FarmRef { 433 pubkey: VALID_PUBKEY.to_string(), 434 d_tag: "invalid".to_string(), 435 }], 436 ) 437 .expect_err("invalid farm d_tag"); 438 assert!(matches!(err, EventEncodeError::InvalidField("farm.d_tag"))); 439 } 440 441 #[test] 442 fn farm_encode_and_list_set_paths() { 443 let tags = farm_build_tags(&sample_farm()).expect("farm tags"); 444 assert!( 445 tags.iter() 446 .any(|tag| tag.first().map(|v| v.as_str()) == Some("d")) 447 ); 448 assert!( 449 tags.iter() 450 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 451 ); 452 assert!( 453 tags.iter() 454 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 455 ); 456 457 let mut farm = sample_farm(); 458 farm.tags = None; 459 farm.location = None; 460 let tags = farm_build_tags(&farm).expect("farm tags without optional fields"); 461 assert!( 462 !tags 463 .iter() 464 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 465 ); 466 assert!( 467 !tags 468 .iter() 469 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 470 ); 471 472 let mut farm = sample_farm(); 473 farm.d_tag = " ".to_string(); 474 let err = farm_build_tags(&farm).expect_err("empty d_tag"); 475 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 476 477 let mut farm = sample_farm(); 478 farm.name = " ".to_string(); 479 let err = farm_build_tags(&farm).expect_err("empty name"); 480 assert!(matches!(err, EventEncodeError::EmptyRequiredField("name"))); 481 482 let mut farm = sample_farm(); 483 farm.location.as_mut().expect("location").geohash = " ".to_string(); 484 let err = farm_build_tags(&farm).expect_err("empty geohash"); 485 assert!(matches!( 486 err, 487 EventEncodeError::EmptyRequiredField("location.geohash") 488 )); 489 490 let mut farm = sample_farm(); 491 farm.location.as_mut().expect("location").geohash = "9q8yy6".to_string(); 492 let err = farm_build_tags(&farm).expect_err("invalid public geohash"); 493 assert!(matches!( 494 err, 495 EventEncodeError::InvalidField("location.geohash") 496 )); 497 498 let tags = farm_ref_tags(&FarmRef { 499 pubkey: VALID_PUBKEY.to_string(), 500 d_tag: VALID_FARM_D_TAG.to_string(), 501 }) 502 .expect("farm ref tags"); 503 assert_eq!(tags.len(), 2); 504 505 let err = farm_ref_tags(&FarmRef { 506 pubkey: " ".to_string(), 507 d_tag: VALID_FARM_D_TAG.to_string(), 508 }) 509 .expect_err("empty farm pubkey"); 510 assert!(matches!( 511 err, 512 EventEncodeError::EmptyRequiredField("farm.pubkey") 513 )); 514 515 let err = farm_ref_tags(&FarmRef { 516 pubkey: VALID_PUBKEY.to_string(), 517 d_tag: " ".to_string(), 518 }) 519 .expect_err("empty farm d_tag"); 520 assert!(matches!( 521 err, 522 EventEncodeError::EmptyRequiredField("farm.d_tag") 523 )); 524 525 let err = farm_ref_tags(&FarmRef { 526 pubkey: VALID_PUBKEY.to_string(), 527 d_tag: "invalid".to_string(), 528 }) 529 .expect_err("invalid farm d_tag"); 530 assert!(matches!(err, EventEncodeError::InvalidField("farm.d_tag"))); 531 532 let err = farm_members_list_set("invalid", ["member"]).expect_err("invalid farm id"); 533 assert!(matches!(err, EventEncodeError::InvalidField("farm_id"))); 534 535 let err = farm_members_list_set(VALID_FARM_D_TAG, [" "]).expect_err("empty member entry"); 536 assert!(matches!( 537 err, 538 EventEncodeError::EmptyRequiredField("entry.values") 539 )); 540 541 let err = farm_operational_listings_list_set(VALID_FARM_D_TAG, VALID_PUBKEY, [" "]) 542 .expect_err("empty listing id"); 543 assert!(matches!( 544 err, 545 EventEncodeError::EmptyRequiredField("listing_id") 546 )); 547 548 let err = farm_operational_listings_list_set(VALID_FARM_D_TAG, VALID_PUBKEY, ["invalid"]) 549 .expect_err("invalid listing id"); 550 assert!(matches!(err, EventEncodeError::InvalidField("listing_id"))); 551 } 552 553 #[test] 554 fn plot_encode_paths() { 555 let tags = plot_build_tags(&sample_plot()).expect("plot tags"); 556 assert!( 557 tags.iter() 558 .any(|tag| tag.first().map(|v| v.as_str()) == Some("a")) 559 ); 560 assert!( 561 tags.iter() 562 .any(|tag| tag.first().map(|v| v.as_str()) == Some("p")) 563 ); 564 assert!( 565 tags.iter() 566 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 567 ); 568 assert!( 569 tags.iter() 570 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 571 ); 572 573 let mut plot = sample_plot(); 574 plot.tags = None; 575 plot.location = None; 576 let tags = plot_build_tags(&plot).expect("plot tags without optional fields"); 577 assert!( 578 !tags 579 .iter() 580 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 581 ); 582 assert!( 583 !tags 584 .iter() 585 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 586 ); 587 588 let err = plot_address(" ", VALID_PLOT_D_TAG).expect_err("empty author pubkey"); 589 assert!(matches!( 590 err, 591 EventEncodeError::EmptyRequiredField("plot.author_pubkey") 592 )); 593 594 let err = plot_address(VALID_PUBKEY, " ").expect_err("empty plot d_tag"); 595 assert!(matches!( 596 err, 597 EventEncodeError::EmptyRequiredField("plot.d_tag") 598 )); 599 600 let err = plot_address(VALID_PUBKEY, "invalid").expect_err("invalid plot d_tag"); 601 assert!(matches!(err, EventEncodeError::InvalidField("plot.d_tag"))); 602 603 let mut plot = sample_plot(); 604 plot.d_tag = " ".to_string(); 605 let err = plot_build_tags(&plot).expect_err("empty plot d_tag"); 606 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 607 608 let mut plot = sample_plot(); 609 plot.name = " ".to_string(); 610 let err = plot_build_tags(&plot).expect_err("empty plot name"); 611 assert!(matches!(err, EventEncodeError::EmptyRequiredField("name"))); 612 613 let mut plot = sample_plot(); 614 plot.farm.pubkey = " ".to_string(); 615 let err = plot_build_tags(&plot).expect_err("empty farm pubkey"); 616 assert!(matches!( 617 err, 618 EventEncodeError::EmptyRequiredField("farm.pubkey") 619 )); 620 621 let mut plot = sample_plot(); 622 plot.farm.d_tag = " ".to_string(); 623 let err = plot_build_tags(&plot).expect_err("empty farm d_tag"); 624 assert!(matches!( 625 err, 626 EventEncodeError::EmptyRequiredField("farm.d_tag") 627 )); 628 629 let mut plot = sample_plot(); 630 plot.farm.d_tag = "invalid".to_string(); 631 let err = plot_build_tags(&plot).expect_err("invalid farm d_tag"); 632 assert!(matches!(err, EventEncodeError::InvalidField("farm.d_tag"))); 633 634 let mut plot = sample_plot(); 635 plot.location.as_mut().expect("location").gcs.geohash = " ".to_string(); 636 let err = plot_build_tags(&plot).expect_err("empty geohash"); 637 assert!(matches!( 638 err, 639 EventEncodeError::EmptyRequiredField("location.gcs.geohash") 640 )); 641 } 642 643 #[test] 644 fn listing_encode_paths() { 645 let listing = sample_listing(); 646 let tags = operational_listing_build_tags(&listing).expect("listing tags"); 647 assert!( 648 tags.iter() 649 .any(|tag| tag.first().map(|v| v.as_str()) == Some("d")) 650 ); 651 652 let full_tags = operational_listing_tags_full(&listing).expect("listing full tags"); 653 assert!(full_tags.iter().any(|tag| { 654 tag.first().map(|v| v.as_str()) == Some("inventory") 655 && tag.get(1).map(|v| v.as_str()) == Some("12") 656 })); 657 assert!(full_tags.iter().any(|tag| { 658 tag.first().map(|v| v.as_str()) == Some("radroots:availability_start") 659 && tag.get(1).map(|v| v.as_str()) == Some("1") 660 })); 661 assert!(full_tags.iter().any(|tag| { 662 tag.first().map(|v| v.as_str()) == Some("expires_at") 663 && tag.get(1).map(|v| v.as_str()) == Some("2") 664 })); 665 assert!(full_tags.iter().any(|tag| { 666 tag.first().map(|v| v.as_str()) == Some("delivery") 667 && tag.get(1).map(|v| v.as_str()) == Some("shipping") 668 })); 669 670 let with_trade_fields: fn() -> OperationalListingTagOptions = 671 OperationalListingTagOptions::with_trade_fields; 672 let option_tags = operational_listing_tags_with_options(&listing, with_trade_fields()) 673 .expect("listing option tags"); 674 assert!(option_tags.iter().any(|tag| { 675 tag.first().map(|v| v.as_str()) == Some("inventory") 676 && tag.get(1).map(|v| v.as_str()) == Some("12") 677 })); 678 679 let mut listing_with_display_fallback = sample_listing(); 680 listing_with_display_fallback.bins[0].quantity = listing_with_display_fallback.bins[0] 681 .quantity 682 .clone() 683 .with_label("fallback-label"); 684 listing_with_display_fallback.bins[0].display_amount = Some(decimal("1")); 685 listing_with_display_fallback.bins[0].display_unit = Some(Unit::Each); 686 listing_with_display_fallback.bins[0].display_label = None; 687 let display_tags = operational_listing_tags_with_options( 688 &listing_with_display_fallback, 689 OperationalListingTagOptions::default(), 690 ) 691 .expect("listing tags with display fallback"); 692 assert!(display_tags.iter().any(|tag| { 693 tag.first().map(|v| v.as_str()) == Some("radroots:bin") 694 && tag.last().map(|v| v.as_str()) == Some("fallback-label") 695 })); 696 697 let mut listing_with_geohash = sample_listing(); 698 listing_with_geohash.location = Some(OperationalListingPublicLocation { 699 primary: "Origin".to_string(), 700 city: Some("Town".to_string()), 701 region: Some("Region".to_string()), 702 country: Some("PE".to_string()), 703 geohash: "6gkzw".to_string(), 704 }); 705 let decoded_tags = operational_listing_tags_with_options( 706 &listing_with_geohash, 707 OperationalListingTagOptions { 708 include_geohash: false, 709 ..OperationalListingTagOptions::default() 710 }, 711 ) 712 .expect("listing tags without geohash tag"); 713 assert!( 714 !decoded_tags 715 .iter() 716 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 717 ); 718 719 let mut listing_with_shared_geohash = sample_listing(); 720 listing_with_shared_geohash.location = Some(OperationalListingPublicLocation { 721 primary: "Origin".to_string(), 722 city: Some("Town".to_string()), 723 region: Some("Region".to_string()), 724 country: Some("PE".to_string()), 725 geohash: "6gkzw".to_string(), 726 }); 727 let shared_geohash_tags = operational_listing_tags_with_options( 728 &listing_with_shared_geohash, 729 OperationalListingTagOptions::default(), 730 ) 731 .expect("listing tags with shared geohash"); 732 assert!(shared_geohash_tags.iter().any(|tag| { 733 tag.first().map(|v| v.as_str()) == Some("g") 734 && tag.get(1).map(|v| v.as_str()) == Some("6gkzw") 735 })); 736 737 let mut listing_without_coordinates = sample_listing(); 738 listing_without_coordinates.location = Some(OperationalListingPublicLocation { 739 primary: "Origin".to_string(), 740 city: Some("Town".to_string()), 741 region: Some("Region".to_string()), 742 country: Some("PE".to_string()), 743 geohash: "6gkzw".to_string(), 744 }); 745 let no_coordinates_tags = operational_listing_tags_with_options( 746 &listing_without_coordinates, 747 OperationalListingTagOptions::default(), 748 ) 749 .expect("listing tags without coordinates"); 750 assert!( 751 !no_coordinates_tags 752 .iter() 753 .any(|tag| tag.first().map(|v| v.as_str()) == Some("L")) 754 ); 755 assert!(no_coordinates_tags.iter().any(|tag| { 756 tag.first().map(|v| v.as_str()) == Some("g") 757 && tag.get(1).map(|v| v.as_str()) == Some("6gkzw") 758 })); 759 760 let mut listing_with_blank_optionals = sample_listing(); 761 listing_with_blank_optionals.product.summary = Some(" ".to_string()); 762 listing_with_blank_optionals.product.process = Some("null".to_string()); 763 listing_with_blank_optionals.product.location = Some(" ".to_string()); 764 listing_with_blank_optionals.product.profile = Some("null".to_string()); 765 listing_with_blank_optionals.product.year = Some(" ".to_string()); 766 listing_with_blank_optionals.location = Some(OperationalListingPublicLocation { 767 primary: " ".to_string(), 768 city: Some(" ".to_string()), 769 region: Some("null".to_string()), 770 country: Some(" ".to_string()), 771 geohash: "6gkzw".to_string(), 772 }); 773 let blank_optional_tags = operational_listing_tags_with_options( 774 &listing_with_blank_optionals, 775 OperationalListingTagOptions::default(), 776 ) 777 .expect_err("blank public location is invalid"); 778 assert!(matches!( 779 blank_optional_tags, 780 EventEncodeError::EmptyRequiredField("location.primary") 781 )); 782 let mut listing_with_blank_product_optionals = sample_listing(); 783 listing_with_blank_product_optionals.product.summary = Some(" ".to_string()); 784 listing_with_blank_product_optionals.product.process = Some("null".to_string()); 785 listing_with_blank_product_optionals.product.location = Some(" ".to_string()); 786 listing_with_blank_product_optionals.product.profile = Some("null".to_string()); 787 listing_with_blank_product_optionals.product.year = Some(" ".to_string()); 788 let blank_optional_tags = operational_listing_tags_with_options( 789 &listing_with_blank_product_optionals, 790 OperationalListingTagOptions::default(), 791 ) 792 .expect("listing tags with blank product optional values"); 793 assert!( 794 !blank_optional_tags 795 .iter() 796 .any(|tag| tag.first().map(|v| v.as_str()) == Some("summary")) 797 ); 798 assert!( 799 !blank_optional_tags 800 .iter() 801 .any(|tag| tag.first().map(|v| v.as_str()) == Some("location")) 802 ); 803 804 let mut listing_without_geohash = sample_listing(); 805 listing_without_geohash.location = Some(OperationalListingPublicLocation { 806 primary: "Origin".to_string(), 807 city: Some("Town".to_string()), 808 region: Some("Region".to_string()), 809 country: Some("PE".to_string()), 810 geohash: "6gkzw".to_string(), 811 }); 812 let without_geohash_tags = operational_listing_tags_with_options( 813 &listing_without_geohash, 814 OperationalListingTagOptions { 815 include_geohash: false, 816 ..OperationalListingTagOptions::default() 817 }, 818 ) 819 .expect("listing tags without geohash"); 820 assert!( 821 !without_geohash_tags 822 .iter() 823 .any(|tag| tag.first().map(|v| v.as_str()) == Some("L")) 824 ); 825 826 let mut listing_without_availability = sample_listing(); 827 listing_without_availability.availability = None; 828 let no_availability_tags = 829 operational_listing_tags_with_options(&listing_without_availability, with_trade_fields()) 830 .expect("listing tags without availability"); 831 assert!( 832 !no_availability_tags 833 .iter() 834 .any(|tag| { tag.first().map(|v| v.as_str()) == Some("radroots:availability_start") }) 835 ); 836 837 let mut listing_pickup = sample_listing(); 838 listing_pickup.delivery_method = Some(OperationalListingDeliveryMethod::Pickup); 839 let pickup_tags = operational_listing_tags_with_options(&listing_pickup, with_trade_fields()) 840 .expect("listing tags with pickup delivery"); 841 assert!(pickup_tags.iter().any(|tag| { 842 tag.first().map(|v| v.as_str()) == Some("delivery") 843 && tag.get(1).map(|v| v.as_str()) == Some("pickup") 844 })); 845 846 let mut listing_local = sample_listing(); 847 listing_local.delivery_method = Some(OperationalListingDeliveryMethod::LocalDelivery); 848 let local_tags = operational_listing_tags_with_options(&listing_local, with_trade_fields()) 849 .expect("listing tags with local delivery"); 850 assert!(local_tags.iter().any(|tag| { 851 tag.first().map(|v| v.as_str()) == Some("delivery") 852 && tag.get(1).map(|v| v.as_str()) == Some("local_delivery") 853 })); 854 855 let mut listing_other_delivery = sample_listing(); 856 listing_other_delivery.delivery_method = Some(OperationalListingDeliveryMethod::Other { 857 method: "courier".to_string(), 858 }); 859 let other_delivery_tags = 860 operational_listing_tags_with_options(&listing_other_delivery, with_trade_fields()) 861 .expect("listing tags with other delivery"); 862 assert!(other_delivery_tags.iter().any(|tag| { 863 tag.first().map(|v| v.as_str()) == Some("delivery") 864 && tag.get(1).map(|v| v.as_str()) == Some("other") 865 && tag.get(2).map(|v| v.as_str()) == Some("courier") 866 })); 867 868 let mut invalid = sample_listing(); 869 invalid.bins[0].display_price = None; 870 invalid.bins[0].display_price_unit = Some(Unit::Each); 871 let err = 872 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 873 .expect_err("missing display price"); 874 assert!(matches!( 875 err, 876 EventEncodeError::EmptyRequiredField("bin.display_price") 877 )); 878 879 let mut invalid = sample_listing(); 880 invalid.bins[0].display_price = Some(money(decimal("10"), Currency::USD)); 881 invalid.bins[0].display_price_unit = None; 882 let err = 883 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 884 .expect_err("missing display price unit"); 885 assert!(matches!( 886 err, 887 EventEncodeError::EmptyRequiredField("bin.display_price_unit") 888 )); 889 890 let mut listing_with_display_price = sample_listing(); 891 listing_with_display_price.bins[0].display_price = Some(money(decimal("10"), Currency::USD)); 892 listing_with_display_price.bins[0].display_price_unit = Some(Unit::Each); 893 let display_price_tags = operational_listing_tags_with_options( 894 &listing_with_display_price, 895 OperationalListingTagOptions::default(), 896 ) 897 .expect("listing tags with display price"); 898 assert!(display_price_tags.iter().any(|tag| { 899 tag.first().map(|v| v.as_str()) == Some("radroots:price") 900 && tag.get(6).map(|v| v.as_str()) == Some("10") 901 && tag.get(7).map(|v| v.as_str()) == Some("each") 902 })); 903 904 let mut invalid = listing_with_display_price.clone(); 905 invalid.bins[0].display_price = Some(money(decimal("10"), Currency::EUR)); 906 let err = 907 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 908 .expect_err("display price currency mismatch"); 909 assert!(matches!( 910 err, 911 EventEncodeError::EmptyRequiredField("bin.display_price") 912 )); 913 914 let mut invalid = sample_listing(); 915 invalid.bins[0].display_amount = None; 916 invalid.bins[0].display_unit = Some(Unit::Each); 917 let err = 918 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 919 .expect_err("missing display amount"); 920 assert!(matches!( 921 err, 922 EventEncodeError::EmptyRequiredField("bin.display_amount") 923 )); 924 925 let mut invalid = sample_listing(); 926 invalid.bins[0].quantity = quantity(decimal("1"), Unit::MassKg); 927 invalid.bins[0].price_per_canonical_unit = quantity_price( 928 money(decimal("10"), Currency::USD), 929 quantity(decimal("1"), Unit::MassG), 930 ); 931 let err = 932 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 933 .expect_err("non-canonical bin quantity"); 934 assert!(matches!( 935 err, 936 EventEncodeError::EmptyRequiredField("bin.quantity") 937 )); 938 939 let mut invalid = sample_listing(); 940 invalid.bins[0].price_per_canonical_unit = quantity_price( 941 money(decimal("10"), Currency::USD), 942 quantity(decimal("2"), Unit::Each), 943 ); 944 let err = 945 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 946 .expect_err("price must be per canonical unit"); 947 assert!(matches!( 948 err, 949 EventEncodeError::EmptyRequiredField("bin.price_per_canonical_unit") 950 )); 951 952 let mut invalid = sample_listing(); 953 invalid.bins[0].price_per_canonical_unit = quantity_price( 954 money(decimal("10"), Currency::USD), 955 quantity(decimal("1"), Unit::MassG), 956 ); 957 let err = 958 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 959 .expect_err("non-convertible bin total price"); 960 assert!(matches!( 961 err, 962 EventEncodeError::EmptyRequiredField("bin.price_per_canonical_unit") 963 )); 964 965 let mut invalid = sample_listing(); 966 invalid.farm.d_tag = " ".to_string(); 967 let err = operational_listing_build_tags(&invalid).expect_err("empty listing farm d_tag"); 968 assert!(matches!( 969 err, 970 EventEncodeError::EmptyRequiredField("farm.d_tag") 971 )); 972 973 let mut invalid = sample_listing(); 974 invalid.bins.clear(); 975 let err = 976 operational_listing_tags_with_options(&invalid, OperationalListingTagOptions::default()) 977 .expect_err("empty bins"); 978 assert!(matches!(err, EventEncodeError::EmptyRequiredField("bins"))); 979 } 980 981 #[test] 982 fn resource_area_encode_and_list_set_paths() { 983 let tags = resource_area_build_tags(&sample_resource_area()).expect("resource area tags"); 984 assert!( 985 tags.iter() 986 .any(|tag| tag.first().map(|v| v.as_str()) == Some("d")) 987 ); 988 assert!( 989 tags.iter() 990 .any(|tag| tag.first().map(|v| v.as_str()) == Some("g")) 991 ); 992 assert!( 993 tags.iter() 994 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 995 ); 996 997 let mut area = sample_resource_area(); 998 area.tags = None; 999 let tags = resource_area_build_tags(&area).expect("resource area tags without optional tags"); 1000 assert!( 1001 !tags 1002 .iter() 1003 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 1004 ); 1005 1006 let mut area = sample_resource_area(); 1007 area.d_tag = " ".to_string(); 1008 let err = resource_area_build_tags(&area).expect_err("empty d_tag"); 1009 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 1010 1011 let mut area = sample_resource_area(); 1012 area.name = " ".to_string(); 1013 let err = resource_area_build_tags(&area).expect_err("empty name"); 1014 assert!(matches!(err, EventEncodeError::EmptyRequiredField("name"))); 1015 1016 let mut area = sample_resource_area(); 1017 area.location.gcs.geohash = " ".to_string(); 1018 let err = resource_area_build_tags(&area).expect_err("empty geohash"); 1019 assert!(matches!( 1020 err, 1021 EventEncodeError::EmptyRequiredField("location.gcs.geohash") 1022 )); 1023 1024 let tags = resource_area_ref_tags(&ResourceAreaRef { 1025 pubkey: VALID_PUBKEY.to_string(), 1026 d_tag: VALID_AREA_D_TAG.to_string(), 1027 }) 1028 .expect("resource area ref tags"); 1029 assert_eq!(tags.len(), 2); 1030 1031 let err = resource_area_ref_tags(&ResourceAreaRef { 1032 pubkey: " ".to_string(), 1033 d_tag: VALID_AREA_D_TAG.to_string(), 1034 }) 1035 .expect_err("empty resource area pubkey"); 1036 assert!(matches!( 1037 err, 1038 EventEncodeError::EmptyRequiredField("resource_area.pubkey") 1039 )); 1040 1041 let err = resource_area_ref_tags(&ResourceAreaRef { 1042 pubkey: VALID_PUBKEY.to_string(), 1043 d_tag: " ".to_string(), 1044 }) 1045 .expect_err("empty resource area d_tag"); 1046 assert!(matches!( 1047 err, 1048 EventEncodeError::EmptyRequiredField("resource_area.d_tag") 1049 )); 1050 1051 let err = resource_area_ref_tags(&ResourceAreaRef { 1052 pubkey: VALID_PUBKEY.to_string(), 1053 d_tag: "invalid".to_string(), 1054 }) 1055 .expect_err("invalid resource area d_tag"); 1056 assert!(matches!( 1057 err, 1058 EventEncodeError::InvalidField("resource_area.d_tag") 1059 )); 1060 1061 let err = resource_area_members_farms_list_set( 1062 "invalid", 1063 vec![FarmRef { 1064 pubkey: VALID_PUBKEY.to_string(), 1065 d_tag: VALID_FARM_D_TAG.to_string(), 1066 }], 1067 ) 1068 .expect_err("invalid area id"); 1069 assert!(matches!(err, EventEncodeError::InvalidField("area_id"))); 1070 1071 let err = 1072 resource_area_stewards_list_set(VALID_AREA_D_TAG, [" "]).expect_err("empty steward entry"); 1073 assert!(matches!( 1074 err, 1075 EventEncodeError::EmptyRequiredField("entry.values") 1076 )); 1077 1078 let stewards = 1079 resource_area_stewards_list_set(VALID_AREA_D_TAG, ["steward"]).expect("stewards list set"); 1080 assert_eq!(stewards.entries.len(), 1); 1081 assert_eq!(stewards.entries[0].tag, "p"); 1082 1083 let err = resource_area_members_farms_list_set( 1084 VALID_AREA_D_TAG, 1085 vec![FarmRef { 1086 pubkey: " ".to_string(), 1087 d_tag: VALID_FARM_D_TAG.to_string(), 1088 }], 1089 ) 1090 .expect_err("empty farm pubkey"); 1091 assert!(matches!( 1092 err, 1093 EventEncodeError::EmptyRequiredField("farm.pubkey") 1094 )); 1095 1096 let err = resource_area_members_farms_list_set( 1097 VALID_AREA_D_TAG, 1098 vec![FarmRef { 1099 pubkey: VALID_PUBKEY.to_string(), 1100 d_tag: " ".to_string(), 1101 }], 1102 ) 1103 .expect_err("empty farm d_tag"); 1104 assert!(matches!( 1105 err, 1106 EventEncodeError::EmptyRequiredField("farm.d_tag") 1107 )); 1108 1109 let err = resource_area_members_farms_list_set( 1110 VALID_AREA_D_TAG, 1111 vec![FarmRef { 1112 pubkey: VALID_PUBKEY.to_string(), 1113 d_tag: "invalid".to_string(), 1114 }], 1115 ) 1116 .expect_err("invalid farm d_tag"); 1117 assert!(matches!(err, EventEncodeError::InvalidField("farm.d_tag"))); 1118 1119 let err = resource_area_members_plots_list_set( 1120 VALID_AREA_D_TAG, 1121 vec![PlotRef { 1122 pubkey: " ".to_string(), 1123 d_tag: VALID_PLOT_D_TAG.to_string(), 1124 }], 1125 ) 1126 .expect_err("empty plot pubkey"); 1127 assert!(matches!( 1128 err, 1129 EventEncodeError::EmptyRequiredField("plot.pubkey") 1130 )); 1131 1132 let err = resource_area_members_plots_list_set( 1133 VALID_AREA_D_TAG, 1134 vec![PlotRef { 1135 pubkey: VALID_PUBKEY.to_string(), 1136 d_tag: " ".to_string(), 1137 }], 1138 ) 1139 .expect_err("empty plot d_tag"); 1140 assert!(matches!( 1141 err, 1142 EventEncodeError::EmptyRequiredField("plot.d_tag") 1143 )); 1144 1145 let err = resource_area_members_plots_list_set( 1146 VALID_AREA_D_TAG, 1147 vec![PlotRef { 1148 pubkey: VALID_PUBKEY.to_string(), 1149 d_tag: "invalid".to_string(), 1150 }], 1151 ) 1152 .expect_err("invalid plot d_tag"); 1153 assert!(matches!(err, EventEncodeError::InvalidField("plot.d_tag"))); 1154 } 1155 1156 #[test] 1157 fn resource_harvest_cap_encode_paths() { 1158 let tags = resource_harvest_cap_build_tags(&sample_resource_cap()).expect("resource cap tags"); 1159 assert!( 1160 tags.iter() 1161 .any(|tag| tag.first().map(|v| v.as_str()) == Some("category")) 1162 ); 1163 1164 let mut cap = sample_resource_cap(); 1165 cap.product.category = None; 1166 let tags = resource_harvest_cap_build_tags(&cap).expect("resource cap tags without category"); 1167 assert!( 1168 !tags 1169 .iter() 1170 .any(|tag| tag.first().map(|v| v.as_str()) == Some("category")) 1171 ); 1172 1173 let mut cap = sample_resource_cap(); 1174 cap.d_tag = " ".to_string(); 1175 let err = resource_harvest_cap_build_tags(&cap).expect_err("empty cap d_tag"); 1176 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 1177 1178 let mut cap = sample_resource_cap(); 1179 cap.d_tag = "invalid".to_string(); 1180 let err = resource_harvest_cap_build_tags(&cap).expect_err("invalid cap d_tag"); 1181 assert!(matches!(err, EventEncodeError::InvalidField("d_tag"))); 1182 1183 let mut cap = sample_resource_cap(); 1184 cap.product.key = " ".to_string(); 1185 let err = resource_harvest_cap_build_tags(&cap).expect_err("empty product key"); 1186 assert!(matches!( 1187 err, 1188 EventEncodeError::EmptyRequiredField("product.key") 1189 )); 1190 1191 let mut cap = sample_resource_cap(); 1192 cap.resource_area.pubkey = " ".to_string(); 1193 let err = resource_harvest_cap_build_tags(&cap).expect_err("empty resource_area pubkey"); 1194 assert!(matches!( 1195 err, 1196 EventEncodeError::EmptyRequiredField("resource_area.pubkey") 1197 )); 1198 1199 let mut cap = sample_resource_cap(); 1200 cap.resource_area.d_tag = " ".to_string(); 1201 let err = resource_harvest_cap_build_tags(&cap).expect_err("empty resource_area d_tag"); 1202 assert!(matches!( 1203 err, 1204 EventEncodeError::EmptyRequiredField("resource_area.d_tag") 1205 )); 1206 1207 let mut cap = sample_resource_cap(); 1208 cap.resource_area.d_tag = "invalid".to_string(); 1209 let err = resource_harvest_cap_build_tags(&cap).expect_err("invalid resource_area d_tag"); 1210 assert!(matches!( 1211 err, 1212 EventEncodeError::InvalidField("resource_area.d_tag") 1213 )); 1214 } 1215 1216 #[test] 1217 fn document_encode_paths() { 1218 let tags = document_build_tags(&sample_document()).expect("document tags"); 1219 assert!( 1220 tags.iter() 1221 .any(|tag| tag.first().map(|v| v.as_str()) == Some("d")) 1222 ); 1223 assert!( 1224 tags.iter() 1225 .any(|tag| tag.first().map(|v| v.as_str()) == Some("p")) 1226 ); 1227 assert!( 1228 tags.iter() 1229 .any(|tag| tag.first().map(|v| v.as_str()) == Some("a")) 1230 ); 1231 assert!( 1232 tags.iter() 1233 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 1234 ); 1235 1236 let mut document = sample_document(); 1237 document.subject.address = None; 1238 document.tags = None; 1239 let tags = document_build_tags(&document).expect("document without optional tags"); 1240 assert!( 1241 !tags 1242 .iter() 1243 .any(|tag| tag.first().map(|v| v.as_str()) == Some("a")) 1244 ); 1245 assert!( 1246 !tags 1247 .iter() 1248 .any(|tag| tag.first().map(|v| v.as_str()) == Some("t")) 1249 ); 1250 1251 let mut document = sample_document(); 1252 document.d_tag = " ".to_string(); 1253 let err = document_build_tags(&document).expect_err("empty d_tag"); 1254 assert!(matches!(err, EventEncodeError::EmptyRequiredField("d_tag"))); 1255 1256 let mut document = sample_document(); 1257 document.doc_type = " ".to_string(); 1258 let err = document_build_tags(&document).expect_err("empty doc_type"); 1259 assert!(matches!( 1260 err, 1261 EventEncodeError::EmptyRequiredField("doc_type") 1262 )); 1263 1264 let mut document = sample_document(); 1265 document.title = " ".to_string(); 1266 let err = document_build_tags(&document).expect_err("empty title"); 1267 assert!(matches!(err, EventEncodeError::EmptyRequiredField("title"))); 1268 1269 let mut document = sample_document(); 1270 document.version = " ".to_string(); 1271 let err = document_build_tags(&document).expect_err("empty version"); 1272 assert!(matches!( 1273 err, 1274 EventEncodeError::EmptyRequiredField("version") 1275 )); 1276 1277 let mut document = sample_document(); 1278 document.subject.pubkey = " ".to_string(); 1279 let err = document_build_tags(&document).expect_err("empty subject pubkey"); 1280 assert!(matches!( 1281 err, 1282 EventEncodeError::EmptyRequiredField("subject.pubkey") 1283 )); 1284 1285 let mut document = sample_document(); 1286 document.subject.address = Some(" ".to_string()); 1287 let err = document_build_tags(&document).expect_err("empty subject address"); 1288 assert!(matches!( 1289 err, 1290 EventEncodeError::EmptyRequiredField("subject.address") 1291 )); 1292 1293 let mut document = sample_document(); 1294 document.d_tag = "invalid".to_string(); 1295 let err = document_build_tags(&document).expect_err("invalid d_tag"); 1296 assert!(matches!(err, EventEncodeError::InvalidField("d_tag"))); 1297 } 1298 1299 #[test] 1300 fn resource_harvest_cap_money_type_sanity() { 1301 let money = money(decimal("1"), Currency::USD); 1302 assert_eq!(money.amount().to_string(), "1"); 1303 }