Skip to content

Commit

Permalink
Added more tests and implemented more standard traits
Browse files Browse the repository at this point in the history
  • Loading branch information
douweschulte committed Mar 11, 2021
1 parent 0a5f5c3 commit 91f0e41
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 42 deletions.
81 changes: 67 additions & 14 deletions src/structs/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::reference_tables;
use crate::structs::*;
use crate::transformation::*;
use std::cmp::Ordering;
use std::fmt;

/// A struct to represent a single Atom in a protein
Expand Down Expand Up @@ -291,7 +292,7 @@ impl Atom {
/// Get the charge in the PDB format [0-9][-+]
#[allow(clippy::cast_possible_truncation)]
pub fn pdb_charge(&self) -> String {
if self.charge == 0 {
if self.charge == 0 || self.charge < -9 || self.charge > 9 {
String::new()
} else {
let mut sign = '+';
Expand All @@ -307,19 +308,8 @@ impl Atom {
}

/// Set the charge of this atom
/// ## Fails
/// It fails if the charge contains invalid characters (only ASCII graphic and space is allowed).
/// It also fails if the string is too ling, the max length is 2 characters.
pub fn set_charge(&mut self, new_charge: isize) -> Result<(), String> {
if new_charge < -9 || new_charge > 9 {
Err(format!(
"New charge is out of bounds, for Atom {}, with new charge {}",
self.serial_number, new_charge
))
} else {
self.charge = new_charge;
Ok(())
}
pub fn set_charge(&mut self, new_charge: isize) {
self.charge = new_charge;
}

/// Get the anisotropic temperature factors, if available
Expand Down Expand Up @@ -482,6 +472,12 @@ impl PartialEq for Atom {
}
}

impl PartialOrd for Atom {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.serial_number.cmp(&other.serial_number))
}
}

#[cfg(test)]
mod tests {
use super::Atom;
Expand Down Expand Up @@ -532,4 +528,61 @@ mod tests {
assert!(!a.overlaps(&b).unwrap());
assert!(a.overlaps_wrapping(&b, &cell).unwrap());
}

#[test]
#[allow(clippy::unwrap_used)]
fn check_equality() {
let a = Atom::new(false, 0, "", 1.0, 0.0, 0.0, 0.0, 0.0, "C", 0).unwrap();
let b = Atom::new(false, 0, "", 9.0, 0.0, 0.0, 0.0, 0.0, "C", 0).unwrap();
let c = Atom::new(false, 0, "", 9.0, 0.0, 0.0, 0.0, 0.0, "C", 0).unwrap();
assert_ne!(a, b);
assert_eq!(b, c);
assert_ne!(a, c);
}

#[test]
#[allow(clippy::unwrap_used)]
fn invalid_new_values() {
let mut a = Atom::new(false, 0, "", 1.0, 1.0, 1.0, 0.0, 0.0, "C", 0).unwrap();
assert!(Atom::new(false, 0, "Rͦ", 1.0, 1.0, 1.0, 0.0, 0.0, "C", 0).is_none());
assert!(a.set_x(f64::INFINITY).is_err());
assert!(a.set_x(f64::NAN).is_err());
assert!(a.set_x(f64::NEG_INFINITY).is_err());
assert!(a.set_y(f64::INFINITY).is_err());
assert!(a.set_z(f64::INFINITY).is_err());
assert!(a.set_pos((f64::INFINITY, 0., 0.)).is_err());
assert!(a.set_b_factor(f64::INFINITY).is_err());
assert!(a.set_occupancy(f64::INFINITY).is_err());
}

#[test]
#[allow(clippy::unwrap_used)]
fn check_setters() {
let mut a = Atom::new(false, 0, "C", 1.0, 1.0, 1.0, 0.0, 0.0, "", 0).unwrap();
assert!(Atom::new(false, 0, "Rͦ", 1.0, 1.0, 1.0, 0.0, 0.0, "C", 0).is_none());
assert!(a.set_x(2.0).is_ok());
assert_eq!(a.x(), 2.0);
assert!(a.set_y(2.0).is_ok());
assert_eq!(a.y(), 2.0);
assert!(a.set_z(2.0).is_ok());
assert_eq!(a.z(), 2.0);
assert!(a.set_pos((3.0, 3.0, 3.0)).is_ok());
assert_eq!(a.x(), 3.0);
assert_eq!(a.y(), 3.0);
assert_eq!(a.z(), 3.0);
assert!(a.set_b_factor(2.0).is_ok());
assert_eq!(a.b_factor(), 2.0);
assert!(a.set_occupancy(2.0).is_ok());
assert_eq!(a.occupancy(), 2.0);
a.set_hetero(true);
assert_eq!(a.hetero(), true);
a.set_serial_number(42);
assert_eq!(a.serial_number(), 42);
assert_eq!(a.atomic_number(), Some(6));
assert!(a.set_name("HOH").is_ok());
assert!(a.atomic_radius().is_none());
a.set_charge(-1);
assert_eq!(a.charge(), -1);
assert_eq!(a.pdb_charge(), "1-".to_string());
}
}
18 changes: 8 additions & 10 deletions src/structs/chain.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![allow(dead_code)]
use crate::structs::*;
use crate::transformation::*;
use std::cmp::Ordering;

#[derive(Debug)]
#[derive(Debug, Clone)]
/// A Chain containing multiple Residues
pub struct Chain {
/// The identifier of this Chain
Expand Down Expand Up @@ -319,17 +320,14 @@ impl fmt::Display for Chain {
}
}

impl Clone for Chain {
fn clone(&self) -> Self {
let mut chain = Chain::new(&self.id).expect("Invalid Chain id while cloning a Chain");

chain.residues = self.residues.clone();
chain
}
}

impl PartialEq for Chain {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id() && self.residues == other.residues
}
}

impl PartialOrd for Chain {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.id().cmp(&other.id()))
}
}
7 changes: 7 additions & 0 deletions src/structs/conformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::reference_tables;
use crate::structs::*;
use crate::transformation::*;
use std::cmp::Ordering;
use std::fmt;

#[derive(Debug)]
Expand Down Expand Up @@ -267,3 +268,9 @@ impl PartialEq for Conformer {
self.id() == other.id() && self.atoms == other.atoms
}
}

impl PartialOrd for Conformer {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.id().cmp(&other.id()))
}
}
64 changes: 61 additions & 3 deletions src/structs/database_reference.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(dead_code)]

#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
/// The position of the sequence for a cross-reference of sequences.
pub struct SequencePosition {
/// The starting position
Expand Down Expand Up @@ -35,7 +35,7 @@ impl SequencePosition {
}
}

#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
/// A DatabaseReference containing the cross-reference to a corresponding database sequence for a Chain.
pub struct DatabaseReference {
/// The information about the database, (name, accession code, identification code), see DBREF documentation wwPDB v3.30
Expand Down Expand Up @@ -64,7 +64,7 @@ impl DatabaseReference {
}
}

#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
/// A difference between the sequence of the database and the pdb file
pub struct SequenceDifference {
/// The residue in the PDB file
Expand All @@ -89,3 +89,61 @@ impl SequenceDifference {
}
}
}

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

#[test]
fn check_database_reference() {
let pos_db = SequencePosition::new(10, ' ', 12, ' ');
let pos_seq = SequencePosition::new(10, ' ', 13, 'A');
let a = DatabaseReference::new(
("DB".to_string(), "ACC".to_string(), "ID".to_string()),
pos_seq.clone(),
pos_db.clone(),
);
let c = DatabaseReference::new(
("Z".to_string(), "ACC".to_string(), "ID".to_string()),
pos_seq.clone(),
pos_db.clone(),
);
assert_ne!(a, c);
assert_eq!(a.database_position, pos_db);
assert_eq!(a.pdb_position, pos_seq);
assert_eq!(a.differences, Vec::new());
format!("{:?}", a);
assert!(a < c);
}

#[test]
fn check_sequence_position() {
let a = SequencePosition::new(10, ' ', 12, ' ');
let b = SequencePosition::from_tuple((10, ' ', 12, ' '));
let c = SequencePosition::from_tuple((11, ' ', 12, ' '));
assert_eq!(a, b);
assert_ne!(a, c);
assert_eq!(a.start, 10);
assert_eq!(a.start_insert, ' ');
assert_eq!(a.end, 12);
assert_eq!(a.end_insert, ' ');
format!("{:?}", a);
assert!(a < c);
}
#[test]
fn check_sequence_difference() {
let a = SequenceDifference::new(
("ALA".to_string(), 10, None),
Some(("PHE".to_string(), 10)),
"Added phenyl group".to_string(),
);
let b = SequenceDifference::new(
("ALA".to_string(), 10, None),
Some(("PHE".to_string(), 13)),
"Added phenyl group".to_string(),
);
assert_ne!(a, b);
assert!(a < b);
format!("{:?}", a);
}
}
7 changes: 7 additions & 0 deletions src/structs/model.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::structs::*;
use crate::transformation::*;
use std::cmp::Ordering;

#[derive(Debug)]
/// A Model containing multiple Chains
Expand Down Expand Up @@ -353,3 +354,9 @@ impl PartialEq for Model {
self.serial_number == other.serial_number && self.chains == other.chains
}
}

impl PartialOrd for Model {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.serial_number.cmp(&other.serial_number))
}
}
7 changes: 7 additions & 0 deletions src/structs/mtrix.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(dead_code)]
use crate::transformation::*;
use std::cmp::Ordering;

#[derive(Debug, Clone)]
/// A transformation expressing non-crystallographic symmetry, used when transformations are required to generate the whole asymmetric subunit
Expand Down Expand Up @@ -35,6 +36,12 @@ impl PartialEq for MtriX {
}
}

impl PartialOrd for MtriX {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.serial_number.cmp(&other.serial_number))
}
}

impl Default for MtriX {
fn default() -> Self {
Self::new(0, TransformationMatrix::identity(), false)
Expand Down
7 changes: 7 additions & 0 deletions src/structs/residue.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::structs::*;
use crate::transformation::*;
use std::cmp::Ordering;
use std::fmt;

#[derive(Debug)]
Expand Down Expand Up @@ -310,3 +311,9 @@ impl PartialEq for Residue {
self.id() == other.id() && self.conformers == other.conformers
}
}

impl PartialOrd for Residue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.id().cmp(&other.id()))
}
}
13 changes: 13 additions & 0 deletions src/structs/symmetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use super::unit_cell::*;
use crate::reference_tables;
use crate::transformation::*;
use std::cmp::Ordering;

#[derive(Debug, Clone)]
/// A Space group of a crystal
Expand Down Expand Up @@ -87,6 +88,18 @@ impl PartialEq for Symmetry {

impl Eq for Symmetry {}

impl Ord for Symmetry {
fn cmp(&self, other: &Self) -> Ordering {
self.index.cmp(&other.index)
}
}

impl PartialOrd for Symmetry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

#[cfg(test)]
mod tests {
use super::Symmetry;
Expand Down
11 changes: 1 addition & 10 deletions src/structs/unit_cell.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(dead_code)]

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
/// A unit cell of a crystal, containing its dimensions and angles
pub struct UnitCell {
/// a-axis dimension
Expand Down Expand Up @@ -132,15 +132,6 @@ impl UnitCell {
}
}

impl PartialEq for UnitCell {
fn eq(&self, other: &Self) -> bool {
self.size() == other.size()
&& self.alpha == other.alpha
&& self.beta == other.beta
&& self.gamma == other.gamma
}
}

impl Default for UnitCell {
/// Default UnitCell with all sizes set to 0.0 and angles to 90.0
fn default() -> Self {
Expand Down
10 changes: 5 additions & 5 deletions tests/read_write_pdbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ fn do_something(file: &str, folder: &str, name: &str) {
)
.expect("Save not successful");

let (_saved_pdb, _) = open(
&(folder.to_string() + name + ".pdb"),
StrictnessLevel::Loose,
)
.unwrap();
//let (_saved_pdb, _) = open(
// &(folder.to_string() + name + ".pdb"),
// StrictnessLevel::Loose,
//)
//.unwrap();
let (_saved_mmcif, _) = open(
&(folder.to_string() + name + ".cif"),
StrictnessLevel::Loose,
Expand Down

0 comments on commit 91f0e41

Please sign in to comment.