1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use arbitrary::Result;

use crate::DocumentBuilder;

const CHARSET_LETTERS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
const CHARSET_NUMBERS: &[u8] = b"0123456789";
const RESERVED_KEYWORDS: &[&str] = &[
    "on",
    "Int",
    "Float",
    "String",
    "Boolean",
    "ID",
    "type",
    "enum",
    "union",
    "extend",
    "scalar",
    "directive",
    "query",
    "mutation",
    "subscription",
    "schema",
    "interface",
];

/// Name is useful to name different elements.
///
/// GraphQL Documents are full of named things: operations, fields, arguments, types, directives, fragments, and variables.
/// All names must follow the same grammatical form.
/// Names in GraphQL are case-sensitive. That is to say name, Name, and NAME all refer to different names.
/// Underscores are significant, which means other_name and othername are two different names
///
/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#Name).
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Name {
    pub(crate) name: String,
}

impl From<Name> for String {
    fn from(val: Name) -> Self {
        val.name
    }
}

impl Name {
    pub const fn new(name: String) -> Self {
        Self { name }
    }
}

impl<'a> DocumentBuilder<'a> {
    /// Create an arbitrary `Name`
    pub fn name(&mut self) -> Result<Name> {
        Ok(Name::new(self.limited_string(30)?))
    }

    /// Create an arbitrary type `Name`
    pub fn type_name(&mut self) -> Result<Name> {
        let mut new_name = self.limited_string(30)?;
        if self.list_existing_type_names().any(|n| n.name == new_name) {
            new_name.push_str(&format!(
                "{}",
                self.object_type_defs.len() + self.enum_type_defs.len() + self.directive_defs.len()
            ));
        }
        Ok(Name::new(new_name))
    }

    /// Create an arbitrary `Name` with an index included in the name (to avoid name conflict)
    pub fn name_with_index(&mut self, index: usize) -> Result<Name> {
        let mut name = self.limited_string(30)?;
        name.push_str(&format!("{}", index));

        Ok(Name::new(name))
    }

    // Mirror what happens in `Arbitrary for String`, but do so with a clamped size.
    pub(crate) fn limited_string(&mut self, max_size: usize) -> Result<String> {
        loop {
            let size = self.u.int_in_range(0..=max_size)?;

            let gen_str = String::from_utf8(
                (0..size)
                    .map(|curr_idx| {
                        let idx = self.u.arbitrary::<usize>()?;

                        // Cannot start with a number
                        let ch = if curr_idx == 0 {
                            // len - 1 to not have a _ at the begining
                            CHARSET_LETTERS[idx % (CHARSET_LETTERS.len() - 1)]
                        } else {
                            let idx = idx % (CHARSET_LETTERS.len() + CHARSET_NUMBERS.len());
                            if idx < CHARSET_LETTERS.len() {
                                CHARSET_LETTERS[idx]
                            } else {
                                CHARSET_NUMBERS[idx - CHARSET_LETTERS.len()]
                            }
                        };

                        Ok(ch)
                    })
                    .collect::<Result<Vec<u8>>>()?,
            )
            .unwrap();
            let new_gen = gen_str.trim_end_matches('_');
            if !new_gen.is_empty() && !RESERVED_KEYWORDS.contains(&new_gen) {
                break Ok(new_gen.to_string());
            }
        }
    }

    fn list_existing_type_names(&self) -> impl Iterator<Item = &Name> {
        self.object_type_defs
            .iter()
            .map(|o| &o.name)
            .chain(self.interface_type_defs.iter().map(|itf| &itf.name))
            .chain(self.enum_type_defs.iter().map(|itf| &itf.name))
            .chain(self.directive_defs.iter().map(|itf| &itf.name))
            .chain(self.union_type_defs.iter().map(|itf| &itf.name))
            .chain(self.input_object_type_defs.iter().map(|itf| &itf.name))
            .chain(self.scalar_type_defs.iter().map(|itf| &itf.name))
            .chain(self.directive_defs.iter().map(|itf| &itf.name))
            .chain(self.fragment_defs.iter().map(|itf| &itf.name))
            .chain(self.operation_defs.iter().filter_map(|op| op.name.as_ref()))
    }
}