AdvancedFuzzer.java

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.example;

import com.code_intelligence.jazzer.api.FuzzedDataProvider;

import com.github.wnameless.json.flattener.*;
import com.github.wnameless.json.base.GsonJsonCore;
import com.github.wnameless.json.base.JsonCore;
import com.github.wnameless.json.unflattener.JsonUnflattener;
import com.github.wnameless.json.unflattener.JsonUnflattenerFactory;

import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class AdvancedFuzzer {
    static StringEscapePolicy[] stringEscapePolicies = {
        StringEscapePolicy.DEFAULT,
        StringEscapePolicy.ALL,
        StringEscapePolicy.ALL_BUT_SLASH,
        StringEscapePolicy.ALL_BUT_UNICODE,
        StringEscapePolicy.ALL_BUT_SLASH_AND_UNICODE
    };

    static FlattenMode[] flattenModes = {
        FlattenMode.NORMAL,
        FlattenMode.MONGODB,
        FlattenMode.KEEP_ARRAYS,
        FlattenMode.KEEP_PRIMITIVE_ARRAYS
    };

    public static void fuzzerTestOneInput(FuzzedDataProvider data) {
        try {
            int testCase = data.consumeInt(0, 5);
            
            switch (testCase) {
                case 0:
                    testKeyTransformer(data);
                    break;
                case 1:
                    testCustomBrackets(data);
                    break;
                case 2:
                    testReaderConstructors(data);
                    break;
                case 3:
                    testIgnoreReservedCharacters(data);
                    break;
                case 4:
                    testStaticMethods(data);
                    break;
                case 5:
                    testMapBasedUnflatten(data);
                    break;
            }
        } catch (RuntimeException ignored) {
        }
    }

    private static void testKeyTransformer(FuzzedDataProvider data) {
        FlattenMode mode = data.pickValue(flattenModes);
        KeyTransformer upperCaseTransformer = key -> key.toUpperCase();
        KeyTransformer prefixTransformer = key -> "prefix_" + key;

        JsonFlattener flattener = new JsonFlattener(new GsonJsonCore(), data.consumeRemainingAsString())
            .withFlattenMode(mode)
            .withKeyTransformer(upperCaseTransformer);
        flattener.flatten();
        flattener.flattenAsMap();

        JsonUnflattener unflattener = new JsonUnflattener(new GsonJsonCore(), data.consumeRemainingAsString())
            .withFlattenMode(mode)
            .withKeyTransformer(prefixTransformer);
        unflattener.unflatten();
        unflattener.unflattenAsMap();
    }

    private static void testCustomBrackets(FuzzedDataProvider data) {
        char leftBracket = data.consumeChar();
        char rightBracket = data.consumeChar();
        
        if (leftBracket == rightBracket) return;
        if (leftBracket == '"' || rightBracket == '"') return;
        if (Character.isLetterOrDigit(leftBracket) || Character.isLetterOrDigit(rightBracket)) return;
        
        FlattenMode mode = data.pickValue(flattenModes);
        String json = data.consumeRemainingAsString();

        try {
            JsonFlattener flattener = new JsonFlattener(json)
                .withFlattenMode(mode)
                .withLeftAndRightBrackets(leftBracket, rightBracket);
            flattener.flatten();
            flattener.flattenAsMap();

            String flat = flattener.flatten();
            JsonUnflattener unflattener = new JsonUnflattener(flat)
                .withFlattenMode(mode)
                .withLeftAndRightBrackets(leftBracket, rightBracket);
            unflattener.unflatten();
            unflattener.unflattenAsMap();
        } catch (IllegalArgumentException ignored) {
        }
    }

    private static void testReaderConstructors(FuzzedDataProvider data) {
        FlattenMode mode = data.pickValue(flattenModes);
        StringEscapePolicy sep = data.pickValue(stringEscapePolicies);
        String json = data.consumeRemainingAsString();

        try {
            JsonFlattener flattener = new JsonFlattener(new GsonJsonCore(), new StringReader(json))
                .withFlattenMode(mode)
                .withStringEscapePolicy(sep);
            flattener.flatten();
            flattener.flattenAsMap();

            String flat = flattener.flatten();
            JsonUnflattener unflattener = new JsonUnflattener(new GsonJsonCore(), new StringReader(flat))
                .withFlattenMode(mode);
            unflattener.unflatten();
            unflattener.unflattenAsMap();
        } catch (Exception ignored) {
        }
    }

    private static void testIgnoreReservedCharacters(FuzzedDataProvider data) {
        FlattenMode mode = data.pickValue(flattenModes);
        StringEscapePolicy sep = data.pickValue(stringEscapePolicies);
        
        JsonFlattener flattener = new JsonFlattener(new GsonJsonCore(), data.consumeRemainingAsString())
            .withFlattenMode(mode)
            .withStringEscapePolicy(sep)
            .ignoreReservedCharacters();
        flattener.flatten();
        flattener.flattenAsMap();

        String flat = flattener.flatten();
        JsonUnflattener unflattener = new JsonUnflattener(new GsonJsonCore(), flat)
            .withFlattenMode(mode);
        unflattener.unflatten();
        unflattener.unflattenAsMap();
    }

    private static void testStaticMethods(FuzzedDataProvider data) {
        String json = data.consumeRemainingAsString();

        try {
            JsonFlattener.flatten(json);
            JsonFlattener.flattenAsMap(json);
        } catch (Exception ignored) {
        }

        try {
            String flat = JsonFlattener.flatten(json);
            JsonUnflattener.unflatten(flat);
            JsonUnflattener.unflattenAsMap(flat);
        } catch (Exception ignored) {
        }
    }

    private static void testMapBasedUnflatten(FuzzedDataProvider data) {
        FlattenMode mode = data.pickValue(flattenModes);
        String json = data.consumeRemainingAsString();

        try {
            JsonFlattener flattener = new JsonFlattener(json).withFlattenMode(mode);
            Map<String, Object> flatMap = flattener.flattenAsMap();

            JsonUnflattener.unflatten(flatMap);
            JsonUnflattener.unflattenAsMap(flatMap);

            Consumer<JsonUnflattener> cfg = ju -> ju.withFlattenMode(mode);
            JsonUnflattenerFactory factory = new JsonUnflattenerFactory(cfg, new GsonJsonCore());
            factory.build(flatMap).unflatten();
            factory.build(flatMap).unflattenAsMap();
        } catch (Exception ignored) {
        }
    }
}