All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.natpryce.snodge.JsonMutator Maven / Gradle / Ivy

Go to download

A small, extensible Java library to randomly mutate JSON documents. Useful for fuzz testing.

There is a newer version: 3.1.0.1
Show newest version
package com.natpryce.snodge;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.natpryce.snodge.internal.EncodedStringMutator;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

import static com.natpryce.snodge.Mutagens.allMutagens;
import static com.natpryce.snodge.internal.JsonWalk.walk;

public class JsonMutator implements Mutator {
    private final Random rng;
    private final Mutagen mutagens;

    public JsonMutator() {
        this(allMutagens());
    }

    public JsonMutator(Mutagen mutagen) {
        this(new Random(), mutagen);
    }

    public JsonMutator(Random rng, Mutagen mutagen) {
        this.rng = rng;
        this.mutagens = mutagen;
    }

    @Override
    public Stream mutate(final JsonElement document, int mutationCount) {
        return mutations(document, mutationCount).stream()
                .map(mutation -> mutation.apply(document));
    }

    private List mutations(JsonElement document, int mutationCount) {
        List selectedMutations = new ArrayList<>(mutationCount);
        AtomicInteger counter = new AtomicInteger(0);

        walk(document)
                .flatMap(path -> mutagens.potentialMutations(document, path, path.apply(document)))
                .sequential()
                .forEach(potentialMutation -> {
                    int count = counter.incrementAndGet();
                    if (count <= mutationCount) {
                        selectedMutations.add(potentialMutation);
                    } else {
                        int index = rng.nextInt(count);
                        if (index < selectedMutations.size()) {
                            selectedMutations.set(index, potentialMutation);
                        }
                    }
                });

        return selectedMutations;
    }

    public Mutator forStrings() {
        Gson gson = new Gson();

        return (originalJsonString, mutationCount) -> {
            JsonElement originalJsonDocument = gson.fromJson(originalJsonString, JsonElement.class);
            return mutate(originalJsonDocument, mutationCount)
                    .map(Object::toString);
        };
    }

    public Mutator forEncodedStrings(Charset encoding) {
        return new EncodedStringMutator(encoding, this.forStrings());
    }

    public Mutator forEncodedStrings(String encodingName) {
        return this.forEncodedStrings(Charset.forName(encodingName));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy