aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java')
-rw-r--r--src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java
new file mode 100644
index 00000000..d2fec3ae
--- /dev/null
+++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java
@@ -0,0 +1,219 @@
+// Copyright 2021 Code Intelligence GmbH
+//
+// 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.code_intelligence.jazzer.autofuzz;
+
+import static com.code_intelligence.jazzer.autofuzz.TestHelpers.autofuzzTestCase;
+import static com.code_intelligence.jazzer.autofuzz.TestHelpers.consumeTestCase;
+import static org.junit.Assert.assertEquals;
+
+import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider;
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.google.json.JsonSanitizer;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import org.junit.Test;
+
+public class MetaTest {
+ public enum TestEnum {
+ FOO,
+ BAR,
+ BAZ,
+ }
+
+ @Test
+ public void testConsume() throws NoSuchMethodException {
+ consumeTestCase(5, "5", Collections.singletonList(5));
+ consumeTestCase((short) 5, "(short) 5", Collections.singletonList((short) 5));
+ consumeTestCase(5L, "5L", Collections.singletonList(5L));
+ consumeTestCase(5.0F, "5.0F", Collections.singletonList(5.0F));
+ consumeTestCase('\n', "'\\n'", Collections.singletonList('\n'));
+ consumeTestCase('\'', "'\\''", Collections.singletonList('\''));
+ consumeTestCase('\\', "'\\\\'", Collections.singletonList('\\'));
+
+ String testString = "foo\n\t\\\"bar";
+ // The expected string is obtained from testString by escaping and wrapping into escaped quotes.
+ consumeTestCase(testString, "\"foo\\n\\t\\\\\\\"bar\"",
+ Arrays.asList((byte) 1, // do not return null
+ testString.length(), testString));
+
+ consumeTestCase(null, "null", Collections.singletonList((byte) 0));
+
+ boolean[] testBooleans = new boolean[] {true, false, true};
+ consumeTestCase(testBooleans, "new boolean[]{true, false, true}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 2 * 3, testBooleans));
+
+ char[] testChars = new char[] {'a', '\n', '\''};
+ consumeTestCase(testChars, "new char[]{'a', '\\n', '\\''}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 2 * 3 * Character.BYTES + Character.BYTES, testChars[0], 2 * 3 * Character.BYTES,
+ 2 * 3 * Character.BYTES, // remaining bytes, 2 times what is needed for 3 chars
+ testChars[1], testChars[2]));
+
+ char[] testNoChars = new char[] {};
+ consumeTestCase(testNoChars, "new char[]{}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 0, 'a', 0, 0));
+
+ short[] testShorts = new short[] {(short) 1, (short) 2, (short) 3};
+ consumeTestCase(testShorts, "new short[]{(short) 1, (short) 2, (short) 3}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 2 * 3 * Short.BYTES, // remaining bytes
+ testShorts));
+
+ long[] testLongs = new long[] {1L, 2L, 3L};
+ consumeTestCase(testLongs, "new long[]{1L, 2L, 3L}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 2 * 3 * Long.BYTES, // remaining bytes
+ testLongs));
+
+ consumeTestCase(new String[] {"foo", "bar", "foo\nbar"},
+ "new java.lang.String[]{\"foo\", \"bar\", \"foo\\nbar\"}",
+ Arrays.asList((byte) 1, // do not return null for the array
+ 32, // remaining bytes
+ (byte) 1, // do not return null for the string
+ 31, // remaining bytes
+ "foo",
+ 28, // remaining bytes
+ 28, // array length
+ (byte) 1, // do not return null for the string
+ 27, // remaining bytes
+ "bar",
+ (byte) 1, // do not return null for the string
+ 23, // remaining bytes
+ "foo\nbar"));
+
+ byte[] testInputStreamBytes = new byte[] {(byte) 1, (byte) 2, (byte) 3};
+ consumeTestCase(new ByteArrayInputStream(testInputStreamBytes),
+ "new java.io.ByteArrayInputStream(new byte[]{(byte) 1, (byte) 2, (byte) 3})",
+ Arrays.asList((byte) 1, // do not return null for the InputStream
+ 2 * 3, // remaining bytes (twice the desired length)
+ testInputStreamBytes));
+
+ consumeTestCase(TestEnum.BAR,
+ String.format("%s.%s", TestEnum.class.getName(), TestEnum.BAR.name()),
+ Arrays.asList((byte) 1, // do not return null for the enum value
+ 1 /* second value */
+ ));
+
+ consumeTestCase(YourAverageJavaClass.class,
+ "com.code_intelligence.jazzer.autofuzz.YourAverageJavaClass.class",
+ Collections.singletonList((byte) 1));
+
+ Type stringStringMapType =
+ MetaTest.class.getDeclaredMethod("returnsStringStringMap").getGenericReturnType();
+ Map<String, String> expectedMap =
+ java.util.stream.Stream
+ .of(new java.util.AbstractMap.SimpleEntry<>("key0", "value0"),
+ new java.util.AbstractMap.SimpleEntry<>("key1", "value1"),
+ new java.util.AbstractMap.SimpleEntry<>("key2", (java.lang.String) null))
+ .collect(java.util.HashMap::new,
+ (map, e) -> map.put(e.getKey(), e.getValue()), java.util.HashMap::putAll);
+ consumeTestCase(stringStringMapType, expectedMap,
+ "java.util.stream.Stream.<java.util.AbstractMap.SimpleEntry<java.lang.String, java.lang.String>>of(new java.util.AbstractMap.SimpleEntry<>(\"key0\", \"value0\"), new java.util.AbstractMap.SimpleEntry<>(\"key1\", \"value1\"), new java.util.AbstractMap.SimpleEntry<>(\"key2\", (java.lang.String) null)).collect(java.util.HashMap::new, (map, e) -> map.put(e.getKey(), e.getValue()), java.util.HashMap::putAll)",
+ Arrays.asList((byte) 1, // do not return null for the map
+ 32, // remaining bytes
+ (byte) 1, // do not return null for the string
+ 31, // remaining bytes
+ "key0",
+ (byte) 1, // do not return null for the string
+ 28, // remaining bytes
+ "value0",
+ 28, // remaining bytes
+ 28, // consumeArrayLength
+ (byte) 1, // do not return null for the string
+ 27, // remaining bytes
+ "key1",
+ (byte) 1, // do not return null for the string
+ 23, // remaining bytes
+ "value1",
+ (byte) 1, // do not return null for the string
+ 27, // remaining bytes
+ "key2",
+ (byte) 0 // *do* return null for the string
+ ));
+ }
+
+ private Map<String, String> returnsStringStringMap() {
+ throw new IllegalStateException(
+ "Should not be called, only exists to construct its generic return type");
+ }
+
+ public static boolean isFive(int arg) {
+ return arg == 5;
+ }
+
+ public static boolean intEquals(int arg1, int arg2) {
+ return arg1 == arg2;
+ }
+
+ @Test
+ public void testAutofuzz() throws NoSuchMethodException {
+ autofuzzTestCase(true, "com.code_intelligence.jazzer.autofuzz.MetaTest.isFive(5)",
+ MetaTest.class.getMethod("isFive", int.class), Collections.singletonList(5));
+ autofuzzTestCase(false, "com.code_intelligence.jazzer.autofuzz.MetaTest.intEquals(5, 4)",
+ MetaTest.class.getMethod("intEquals", int.class, int.class), Arrays.asList(5, 4));
+ autofuzzTestCase("foobar", "(\"foo\").concat(\"bar\")",
+ String.class.getMethod("concat", String.class),
+ Arrays.asList((byte) 1, 6, "foo", (byte) 1, 6, "bar"));
+ autofuzzTestCase("jazzer", "new java.lang.String(\"jazzer\")",
+ String.class.getConstructor(String.class), Arrays.asList((byte) 1, 12, "jazzer"));
+ autofuzzTestCase("\"jazzer\"", "com.google.json.JsonSanitizer.sanitize(\"jazzer\")",
+ JsonSanitizer.class.getMethod("sanitize", String.class),
+ Arrays.asList((byte) 1, 12, "jazzer"));
+
+ FuzzedDataProvider data =
+ CannedFuzzedDataProvider.create(Arrays.asList((byte) 1, // do not return null
+ 8, // remainingBytes
+ "buzz"));
+ assertEquals("fizzbuzz", new Meta(null).autofuzz(data, "fizz" ::concat));
+ }
+
+ // Regression test for https://github.com/CodeIntelligenceTesting/jazzer/issues/465.
+ @Test
+ public void testPrivateInterface() {
+ autofuzzTestCase(null,
+ "com.code_intelligence.jazzer.autofuzz.OpinionatedClass.doStuffWithPrivateInterface(((java.util.function.Supplier<com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation>) (() -> {com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation autofuzzVariable0 = new com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation(); return autofuzzVariable0;})).get())",
+ OpinionatedClass.class.getDeclaredMethods()[0],
+ Arrays.asList((byte) 1, // do not return null
+ 0, // first (and only) class on the classpath
+ (byte) 1, // do not return null
+ 0 /* first (and only) constructor*/));
+ }
+
+ Class<?>[] returnsClassArray() {
+ throw new IllegalStateException(
+ "Should not be called, only exists to construct its generic return type");
+ }
+
+ @Test
+ public void testGetRawType() throws NoSuchMethodException {
+ Type classArrayType =
+ MetaTest.class.getDeclaredMethod("returnsClassArray").getGenericReturnType();
+ assertEquals(Class[].class, Meta.getRawType(classArrayType));
+ }
+}
+
+class OpinionatedClass {
+ public static void doStuffWithPrivateInterface(
+ @SuppressWarnings("unused") PrivateInterface thing) {}
+
+ private interface PrivateInterface {}
+
+ public static class PublicImplementation implements PrivateInterface {}
+}