xref: /aosp_15_r20/external/jazzer-api/src/test/java/com/code_intelligence/jazzer/autofuzz/MetaTest.java (revision 33edd6723662ea34453766bfdca85dbfdd5342b8)
1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.autofuzz;
16 
17 import static com.code_intelligence.jazzer.autofuzz.TestHelpers.autofuzzTestCase;
18 import static com.code_intelligence.jazzer.autofuzz.TestHelpers.consumeTestCase;
19 import static org.junit.Assert.assertEquals;
20 
21 import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider;
22 import com.code_intelligence.jazzer.api.FuzzedDataProvider;
23 import com.google.json.JsonSanitizer;
24 import java.io.ByteArrayInputStream;
25 import java.lang.reflect.Type;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Map;
29 import org.junit.Test;
30 
31 public class MetaTest {
32   public enum TestEnum {
33     FOO,
34     BAR,
35     BAZ,
36   }
37 
38   @Test
testConsume()39   public void testConsume() throws NoSuchMethodException {
40     consumeTestCase(5, "5", Collections.singletonList(5));
41     consumeTestCase((short) 5, "(short) 5", Collections.singletonList((short) 5));
42     consumeTestCase(5L, "5L", Collections.singletonList(5L));
43     consumeTestCase(5.0F, "5.0F", Collections.singletonList(5.0F));
44     consumeTestCase('\n', "'\\n'", Collections.singletonList('\n'));
45     consumeTestCase('\'', "'\\''", Collections.singletonList('\''));
46     consumeTestCase('\\', "'\\\\'", Collections.singletonList('\\'));
47 
48     String testString = "foo\n\t\\\"bar";
49     // The expected string is obtained from testString by escaping and wrapping into escaped quotes.
50     consumeTestCase(testString, "\"foo\\n\\t\\\\\\\"bar\"",
51         Arrays.asList((byte) 1, // do not return null
52             testString.length(), testString));
53 
54     consumeTestCase(null, "null", Collections.singletonList((byte) 0));
55 
56     boolean[] testBooleans = new boolean[] {true, false, true};
57     consumeTestCase(testBooleans, "new boolean[]{true, false, true}",
58         Arrays.asList((byte) 1, // do not return null for the array
59             2 * 3, testBooleans));
60 
61     char[] testChars = new char[] {'a', '\n', '\''};
62     consumeTestCase(testChars, "new char[]{'a', '\\n', '\\''}",
63         Arrays.asList((byte) 1, // do not return null for the array
64             2 * 3 * Character.BYTES + Character.BYTES, testChars[0], 2 * 3 * Character.BYTES,
65             2 * 3 * Character.BYTES, // remaining bytes, 2 times what is needed for 3 chars
66             testChars[1], testChars[2]));
67 
68     char[] testNoChars = new char[] {};
69     consumeTestCase(testNoChars, "new char[]{}",
70         Arrays.asList((byte) 1, // do not return null for the array
71             0, 'a', 0, 0));
72 
73     short[] testShorts = new short[] {(short) 1, (short) 2, (short) 3};
74     consumeTestCase(testShorts, "new short[]{(short) 1, (short) 2, (short) 3}",
75         Arrays.asList((byte) 1, // do not return null for the array
76             2 * 3 * Short.BYTES, // remaining bytes
77             testShorts));
78 
79     long[] testLongs = new long[] {1L, 2L, 3L};
80     consumeTestCase(testLongs, "new long[]{1L, 2L, 3L}",
81         Arrays.asList((byte) 1, // do not return null for the array
82             2 * 3 * Long.BYTES, // remaining bytes
83             testLongs));
84 
85     consumeTestCase(new String[] {"foo", "bar", "foo\nbar"},
86         "new java.lang.String[]{\"foo\", \"bar\", \"foo\\nbar\"}",
87         Arrays.asList((byte) 1, // do not return null for the array
88             32, // remaining bytes
89             (byte) 1, // do not return null for the string
90             31, // remaining bytes
91             "foo",
92             28, // remaining bytes
93             28, // array length
94             (byte) 1, // do not return null for the string
95             27, // remaining bytes
96             "bar",
97             (byte) 1, // do not return null for the string
98             23, // remaining bytes
99             "foo\nbar"));
100 
101     byte[] testInputStreamBytes = new byte[] {(byte) 1, (byte) 2, (byte) 3};
102     consumeTestCase(new ByteArrayInputStream(testInputStreamBytes),
103         "new java.io.ByteArrayInputStream(new byte[]{(byte) 1, (byte) 2, (byte) 3})",
104         Arrays.asList((byte) 1, // do not return null for the InputStream
105             2 * 3, // remaining bytes (twice the desired length)
106             testInputStreamBytes));
107 
108     consumeTestCase(TestEnum.BAR,
109         String.format("%s.%s", TestEnum.class.getName(), TestEnum.BAR.name()),
110         Arrays.asList((byte) 1, // do not return null for the enum value
111             1 /* second value */
112             ));
113 
114     consumeTestCase(YourAverageJavaClass.class,
115         "com.code_intelligence.jazzer.autofuzz.YourAverageJavaClass.class",
116         Collections.singletonList((byte) 1));
117 
118     Type stringStringMapType =
119         MetaTest.class.getDeclaredMethod("returnsStringStringMap").getGenericReturnType();
120     Map<String, String> expectedMap =
121         java.util.stream.Stream
122             .of(new java.util.AbstractMap.SimpleEntry<>("key0", "value0"),
123                 new java.util.AbstractMap.SimpleEntry<>("key1", "value1"),
124                 new java.util.AbstractMap.SimpleEntry<>("key2", (java.lang.String) null))
125             .collect(java.util.HashMap::new,
126                 (map, e) -> map.put(e.getKey(), e.getValue()), java.util.HashMap::putAll);
127     consumeTestCase(stringStringMapType, expectedMap,
128         "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)",
129         Arrays.asList((byte) 1, // do not return null for the map
130             32, // remaining bytes
131             (byte) 1, // do not return null for the string
132             31, // remaining bytes
133             "key0",
134             (byte) 1, // do not return null for the string
135             28, // remaining bytes
136             "value0",
137             28, // remaining bytes
138             28, // consumeArrayLength
139             (byte) 1, // do not return null for the string
140             27, // remaining bytes
141             "key1",
142             (byte) 1, // do not return null for the string
143             23, // remaining bytes
144             "value1",
145             (byte) 1, // do not return null for the string
146             27, // remaining bytes
147             "key2",
148             (byte) 0 // *do* return null for the string
149             ));
150   }
151 
returnsStringStringMap()152   private Map<String, String> returnsStringStringMap() {
153     throw new IllegalStateException(
154         "Should not be called, only exists to construct its generic return type");
155   }
156 
isFive(int arg)157   public static boolean isFive(int arg) {
158     return arg == 5;
159   }
160 
intEquals(int arg1, int arg2)161   public static boolean intEquals(int arg1, int arg2) {
162     return arg1 == arg2;
163   }
164 
165   @Test
testAutofuzz()166   public void testAutofuzz() throws NoSuchMethodException {
167     autofuzzTestCase(true, "com.code_intelligence.jazzer.autofuzz.MetaTest.isFive(5)",
168         MetaTest.class.getMethod("isFive", int.class), Collections.singletonList(5));
169     autofuzzTestCase(false, "com.code_intelligence.jazzer.autofuzz.MetaTest.intEquals(5, 4)",
170         MetaTest.class.getMethod("intEquals", int.class, int.class), Arrays.asList(5, 4));
171     autofuzzTestCase("foobar", "(\"foo\").concat(\"bar\")",
172         String.class.getMethod("concat", String.class),
173         Arrays.asList((byte) 1, 6, "foo", (byte) 1, 6, "bar"));
174     autofuzzTestCase("jazzer", "new java.lang.String(\"jazzer\")",
175         String.class.getConstructor(String.class), Arrays.asList((byte) 1, 12, "jazzer"));
176     autofuzzTestCase("\"jazzer\"", "com.google.json.JsonSanitizer.sanitize(\"jazzer\")",
177         JsonSanitizer.class.getMethod("sanitize", String.class),
178         Arrays.asList((byte) 1, 12, "jazzer"));
179 
180     FuzzedDataProvider data =
181         CannedFuzzedDataProvider.create(Arrays.asList((byte) 1, // do not return null
182             8, // remainingBytes
183             "buzz"));
184     assertEquals("fizzbuzz", new Meta(null).autofuzz(data, "fizz" ::concat));
185   }
186 
187   // Regression test for https://github.com/CodeIntelligenceTesting/jazzer/issues/465.
188   @Test
testPrivateInterface()189   public void testPrivateInterface() {
190     autofuzzTestCase(null,
191         "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())",
192         OpinionatedClass.class.getDeclaredMethods()[0],
193         Arrays.asList((byte) 1, // do not return null
194             0, // first (and only) class on the classpath
195             (byte) 1, // do not return null
196             0 /* first (and only) constructor*/));
197   }
198 
returnsClassArray()199   Class<?>[] returnsClassArray() {
200     throw new IllegalStateException(
201         "Should not be called, only exists to construct its generic return type");
202   }
203 
204   @Test
testGetRawType()205   public void testGetRawType() throws NoSuchMethodException {
206     Type classArrayType =
207         MetaTest.class.getDeclaredMethod("returnsClassArray").getGenericReturnType();
208     assertEquals(Class[].class, Meta.getRawType(classArrayType));
209   }
210 }
211 
212 class OpinionatedClass {
doStuffWithPrivateInterface( @uppressWarnings"unused") PrivateInterface thing)213   public static void doStuffWithPrivateInterface(
214       @SuppressWarnings("unused") PrivateInterface thing) {}
215 
216   private interface PrivateInterface {}
217 
218   public static class PublicImplementation implements PrivateInterface {}
219 }
220