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
use util::pick;

use binjs_meta::spec::*;
use std::iter;

use rand;
use rand::distributions::Alphanumeric;
use serde_json::Value as JSON;

pub trait Pick {
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON;
}

pub struct Picker;
impl Pick for Picker {
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        syntax.get_root().random(syntax, rng, depth_limit)
    }
}

impl Pick for NamedType {
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        match *self {
            NamedType::Interface(ref interface) => interface.random(syntax, rng, depth_limit),
            NamedType::Typedef(ref typedef) => typedef.random(syntax, rng, depth_limit),
            NamedType::StringEnum(ref string_enum) => {
                let string = pick(rng, &string_enum.strings());
                JSON::from(string.clone())
            }
        }
    }
}

impl Pick for TypeSpec {
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        const MAX_ARRAY_LEN: usize = 16;
        match *self {
            TypeSpec::Array {
                supports_empty,
                contents: ref type_,
            } => {
                if supports_empty && depth_limit <= 0 {
                    return JSON::Array(vec![]);
                }
                let min = if supports_empty { 0 } else { 1 };
                let len = rng.gen_range(min, MAX_ARRAY_LEN);
                let mut buf = Vec::with_capacity(len);
                for _ in 0..len {
                    buf.push(type_.random(syntax, rng, depth_limit - 1));
                }
                JSON::Array(buf)
            }
            TypeSpec::NamedType(ref name) => {
                if let Some(named) = syntax.get_type_by_name(name) {
                    named.random(syntax, rng, depth_limit)
                } else {
                    panic!("Could not find named type {:?}", name)
                }
            }
            TypeSpec::TypeSum(ref types) => {
                let type_ = pick(rng, types.types());
                type_.random(syntax, rng, depth_limit)
            }
            TypeSpec::Boolean => JSON::Bool(rng.gen()),
            TypeSpec::String | TypeSpec::PropertyKey | TypeSpec::IdentifierName => {
                const MAX_STRING_LEN: usize = 10;
                let len = rng.gen_range(0, MAX_STRING_LEN);
                let string: String = iter::repeat(())
                    .map(|()| rng.sample(Alphanumeric))
                    .take(len)
                    .collect();
                JSON::from(string)
            }
            TypeSpec::Number => JSON::from(rng.gen::<f64>()),
            TypeSpec::Void => JSON::Null,
            TypeSpec::Offset | TypeSpec::UnsignedLong => {
                JSON::from(rng.gen_range(0, u32::max_value()))
            }
        }
    }
}

impl Pick for Type {
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        if self.is_optional() {
            // 10% chance of returning the default value
            if depth_limit <= 0 || rng.gen_range(0, 10) > 0 {
                return JSON::Null;
            }
        }
        self.spec.random(syntax, rng, depth_limit)
    }
}

impl Pick for Interface {
    /// Generate a random instance of this interface matching the syntax.
    fn random<T: rand::Rng>(&self, syntax: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        let mut obj = serde_json::Map::with_capacity(self.contents().fields().len());
        for field in self.contents().fields() {
            let value = field.type_().random(syntax, rng, depth_limit - 1);
            obj.insert(field.name().to_str().to_string(), value);
        }
        serde_json::Value::Object(obj)
    }
}

impl Pick for Spec {
    /// Generate a random AST matching the grammar.
    ///
    /// `depth_limit` is used as *hint* to control the depth of the tree
    fn random<T: rand::Rng>(&self, _: &Spec, rng: &mut T, depth_limit: isize) -> JSON {
        let root = self
            .interfaces_by_name()
            .get(&self.get_root_name())
            .expect("Root interface doesn't exist");
        root.random(self, rng, depth_limit)
    }
}