diff options
Diffstat (limited to 'src/test/java/com/code_intelligence/jazzer/autofuzz')
9 files changed, 757 insertions, 0 deletions
diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/AutofuzzCodegenVisitorTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/AutofuzzCodegenVisitorTest.java new file mode 100644 index 00000000..814292e6 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/AutofuzzCodegenVisitorTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2022 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.AutofuzzCodegenVisitor.escapeForLiteral; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class AutofuzzCodegenVisitorTest { + @Test + public void escapeForLiteralTest() { + assertEquals("\\t", escapeForLiteral("\t")); + assertEquals("\\\\\\t", escapeForLiteral("\\\t")); + assertEquals("\\b", escapeForLiteral("\b")); + assertEquals("\\\\\\b", escapeForLiteral("\\\b")); + assertEquals("\\n", escapeForLiteral("\n")); + assertEquals("\\\\\\n", escapeForLiteral("\\\n")); + assertEquals("\\r", escapeForLiteral("\r")); + assertEquals("\\\\\\r", escapeForLiteral("\\\r")); + assertEquals("\\f", escapeForLiteral("\f")); + assertEquals("\\\\\\f", escapeForLiteral("\\\f")); + assertEquals("\\'", escapeForLiteral("'")); + assertEquals("\\\\\\'", escapeForLiteral("\\'")); + assertEquals("\\\"", escapeForLiteral("\"")); + assertEquals("\\\\\\\"", escapeForLiteral("\\\"")); + assertEquals("\\\\", escapeForLiteral("\\")); + } +} diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel new file mode 100644 index 00000000..a5ee59b1 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/BUILD.bazel @@ -0,0 +1,93 @@ +java_test( + name = "MetaTest", + size = "small", + srcs = [ + "MetaTest.java", + ], + env = { + "JAZZER_AUTOFUZZ_DEBUG": "1", + # Also consider implementing classes from com.code_intelligence.jazzer.*. + "JAZZER_AUTOFUZZ_TESTING": "1", + }, + test_class = "com.code_intelligence.jazzer.autofuzz.MetaTest", + deps = [ + ":test_helpers", + "//src/main/java/com/code_intelligence/jazzer/api", + "//src/main/java/com/code_intelligence/jazzer/autofuzz", + "@maven//:com_mikesamuel_json_sanitizer", + "@maven//:junit_junit", + ], +) + +java_test( + name = "InterfaceCreationTest", + size = "small", + srcs = [ + "InterfaceCreationTest.java", + ], + env = { + "JAZZER_AUTOFUZZ_DEBUG": "1", + # Also consider implementing classes from com.code_intelligence.jazzer.*. + "JAZZER_AUTOFUZZ_TESTING": "1", + }, + test_class = "com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest", + deps = [ + ":test_helpers", + "@maven//:junit_junit", + ], +) + +java_test( + name = "BuilderPatternTest", + size = "small", + srcs = [ + "BuilderPatternTest.java", + ], + env = { + "JAZZER_AUTOFUZZ_DEBUG": "1", + }, + test_class = "com.code_intelligence.jazzer.autofuzz.BuilderPatternTest", + deps = [ + ":test_helpers", + "@maven//:junit_junit", + ], +) + +java_test( + name = "SettersTest", + size = "small", + srcs = [ + "SettersTest.java", + ], + env = { + "JAZZER_AUTOFUZZ_DEBUG": "1", + }, + test_class = "com.code_intelligence.jazzer.autofuzz.SettersTest", + deps = [ + ":test_helpers", + "//src/test/java/com/code_intelligence/jazzer/autofuzz/testdata:test_data", + "@maven//:junit_junit", + ], +) + +java_test( + name = "AutofuzzCodegenVisitorTest", + srcs = [ + "AutofuzzCodegenVisitorTest.java", + ], + test_class = "com.code_intelligence.jazzer.autofuzz.AutofuzzCodegenVisitorTest", + deps = [ + "//src/main/java/com/code_intelligence/jazzer/autofuzz", + "@maven//:junit_junit", + ], +) + +java_library( + name = "test_helpers", + srcs = ["TestHelpers.java"], + deps = [ + "//src/main/java/com/code_intelligence/jazzer/api", + "//src/main/java/com/code_intelligence/jazzer/autofuzz", + "@maven//:junit_junit", + ], +) diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/BuilderPatternTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/BuilderPatternTest.java new file mode 100644 index 00000000..a602d712 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/BuilderPatternTest.java @@ -0,0 +1,103 @@ +// 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.consumeTestCase; + +import java.util.Arrays; +import java.util.Objects; +import org.junit.Test; + +class Employee { + private final String firstName; + private final String lastName; + private final String jobTitle; + private final int age; + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Employee hero = (Employee) o; + return age == hero.age && Objects.equals(firstName, hero.firstName) + && Objects.equals(lastName, hero.lastName) && Objects.equals(jobTitle, hero.jobTitle); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, jobTitle, age); + } + + private Employee(Builder builder) { + this.jobTitle = builder.jobTitle; + this.firstName = builder.firstName; + this.lastName = builder.lastName; + this.age = builder.age; + } + + public static class Builder { + private final String firstName; + private final String lastName; + private String jobTitle; + private int age; + + public Builder(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Builder withAge(int age) { + this.age = age; + return this; + } + + public Builder withJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + return this; + } + + public Employee build() { + return new Employee(this); + } + } +} + +public class BuilderPatternTest { + @Test + public void testBuilderPattern() { + consumeTestCase(new Employee.Builder("foo", "bar").withAge(20).withJobTitle("baz").build(), + "new com.code_intelligence.jazzer.autofuzz.Employee.Builder(\"foo\", \"bar\").withAge(20).withJobTitle(\"baz\").build()", + Arrays.asList((byte) 1, // do not return null + 0, // Select the first Builder + 2, // Select two Builder methods returning a builder object (fluent design) + 0, // Select the first build method + 0, // pick the first remaining builder method (withAge) + 0, // pick the first remaining builder method (withJobTitle) + 0, // pick the first build method + (byte) 1, // do not return null + 6, // remaining bytes + "foo", // firstName + (byte) 1, // do not return null + 6, // remaining bytes + "bar", // lastName + 20, // age + (byte) 1, // do not return null + 6, // remaining bytes + "baz" // jobTitle + )); + } +} diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java new file mode 100644 index 00000000..3fecb973 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/InterfaceCreationTest.java @@ -0,0 +1,110 @@ +// 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.consumeTestCase; + +import java.util.Arrays; +import java.util.Objects; +import org.junit.Test; + +public class InterfaceCreationTest { + public interface InterfaceA { + void foo(); + + void bar(); + } + + public static abstract class ClassA1 implements InterfaceA { + @Override + public void foo() {} + } + + public static class ClassB1 extends ClassA1 { + int n; + + public ClassB1(int _n) { + n = _n; + } + + @Override + public void bar() {} + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClassB1 classB1 = (ClassB1) o; + return n == classB1.n; + } + + @Override + public int hashCode() { + return Objects.hash(n); + } + } + + public static class ClassB2 implements InterfaceA { + String s; + + public ClassB2(String _s) { + s = _s; + } + + @Override + public void foo() {} + + @Override + public void bar() {} + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClassB2 classB2 = (ClassB2) o; + return Objects.equals(s, classB2.s); + } + + @Override + public int hashCode() { + return Objects.hash(s); + } + } + @Test + public void testConsumeInterface() { + consumeTestCase(InterfaceA.class, new ClassB1(5), + "(com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest.InterfaceA) new com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest.ClassB1(5)", + Arrays.asList((byte) 1, // do not return null + 0, // pick ClassB1 + (byte) 1, // do not return null + 0, // pick first constructor + 5 // arg for ClassB1 constructor + )); + consumeTestCase(InterfaceA.class, new ClassB2("test"), + "(com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest.InterfaceA) new com.code_intelligence.jazzer.autofuzz.InterfaceCreationTest.ClassB2(\"test\")", + Arrays.asList((byte) 1, // do not return null + 1, // pick ClassB2 + (byte) 1, // do not return null + 0, // pick first constructor + (byte) 1, // do not return null + 8, // remaining bytes + "test" // arg for ClassB2 constructor + )); + } +} 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 {} +} diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java new file mode 100644 index 00000000..7c869531 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/SettersTest.java @@ -0,0 +1,43 @@ +// 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.consumeTestCase; + +import com.code_intelligence.jazzer.autofuzz.testdata.EmployeeWithSetters; +import java.util.Arrays; +import org.junit.Test; + +public class SettersTest { + @Test + public void testEmptyConstructorWithSetters() { + EmployeeWithSetters employee = new EmployeeWithSetters(); + employee.setFirstName("foo"); + employee.setAge(26); + + consumeTestCase(employee, + "((java.util.function.Supplier<com.code_intelligence.jazzer.autofuzz.testdata.EmployeeWithSetters>) (() -> {com.code_intelligence.jazzer.autofuzz.testdata.EmployeeWithSetters autofuzzVariable0 = new com.code_intelligence.jazzer.autofuzz.testdata.EmployeeWithSetters(); autofuzzVariable0.setFirstName(\"foo\"); autofuzzVariable0.setAge(26); return autofuzzVariable0;})).get()", + Arrays.asList((byte) 1, // do not return null for EmployeeWithSetters + 0, // pick first constructor + 2, // pick two setters + 1, // pick second setter + 0, // pick first setter + (byte) 1, // do not return null for String + 6, // remaining bytes + "foo", // setFirstName + 26 // setAge + )); + } +} diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/TestHelpers.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/TestHelpers.java new file mode 100644 index 00000000..89f9c968 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/TestHelpers.java @@ -0,0 +1,85 @@ +// 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 org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import java.io.ByteArrayInputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.List; + +class TestHelpers { + static void assertGeneralEquals(Object expected, Object actual) { + Class<?> type = expected != null ? expected.getClass() : Object.class; + if (type.isArray()) { + if (type.getComponentType() == boolean.class) { + assertArrayEquals((boolean[]) expected, (boolean[]) actual); + } else if (type.getComponentType() == char.class) { + assertArrayEquals((char[]) expected, (char[]) actual); + } else if (type.getComponentType() == short.class) { + assertArrayEquals((short[]) expected, (short[]) actual); + } else if (type.getComponentType() == long.class) { + assertArrayEquals((long[]) expected, (long[]) actual); + } else { + assertArrayEquals((Object[]) expected, (Object[]) actual); + } + } else if (type == ByteArrayInputStream.class) { + ByteArrayInputStream expectedStream = (ByteArrayInputStream) expected; + ByteArrayInputStream actualStream = (ByteArrayInputStream) actual; + assertArrayEquals(readAllBytes(expectedStream), readAllBytes(actualStream)); + } else { + assertEquals(expected, actual); + } + } + + static void consumeTestCase( + Object expectedResult, String expectedResultString, List<Object> cannedData) { + Class<?> type = expectedResult != null ? expectedResult.getClass() : Object.class; + consumeTestCase(type, expectedResult, expectedResultString, cannedData); + } + + static void consumeTestCase( + Type type, Object expectedResult, String expectedResultString, List<Object> cannedData) { + AutofuzzCodegenVisitor visitor = new AutofuzzCodegenVisitor(); + FuzzedDataProvider data = CannedFuzzedDataProvider.create(cannedData); + assertGeneralEquals(expectedResult, new Meta(null).consume(data, type, visitor)); + assertEquals(expectedResultString, visitor.generate()); + } + + static void autofuzzTestCase(Object expectedResult, String expectedResultString, Executable func, + List<Object> cannedData) { + AutofuzzCodegenVisitor visitor = new AutofuzzCodegenVisitor(); + FuzzedDataProvider data = CannedFuzzedDataProvider.create(cannedData); + if (func instanceof Method) { + assertGeneralEquals(expectedResult, new Meta(null).autofuzz(data, (Method) func, visitor)); + } else { + assertGeneralEquals( + expectedResult, new Meta(null).autofuzz(data, (Constructor<?>) func, visitor)); + } + assertEquals(expectedResultString, visitor.generate()); + } + + private static byte[] readAllBytes(ByteArrayInputStream in) { + byte[] result = new byte[in.available()]; + in.read(result, 0, in.available()); + return result; + } +} diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel b/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel new file mode 100644 index 00000000..c2c68803 --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/BUILD.bazel @@ -0,0 +1,5 @@ +java_library( + name = "test_data", + srcs = glob(["*.java"]), + visibility = ["//visibility:public"], +) diff --git a/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java b/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java new file mode 100644 index 00000000..2c76a61f --- /dev/null +++ b/src/test/java/com/code_intelligence/jazzer/autofuzz/testdata/EmployeeWithSetters.java @@ -0,0 +1,56 @@ +// 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.testdata; + +import java.util.Objects; + +public class EmployeeWithSetters { + private String firstName; + private String lastName; + private String jobTitle; + private int age; + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + EmployeeWithSetters hero = (EmployeeWithSetters) o; + return age == hero.age && Objects.equals(firstName, hero.firstName) + && Objects.equals(lastName, hero.lastName) && Objects.equals(jobTitle, hero.jobTitle); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, jobTitle, age); + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public void setJobTitle(String jobTitle) { + this.jobTitle = jobTitle; + } + + public void setAge(int age) { + this.age = age; + } +} |