001package daikon.test.diff; 002 003import static java.util.logging.Level.INFO; 004import static org.junit.Assert.assertEquals; 005 006import daikon.*; 007import daikon.config.*; 008import daikon.diff.*; 009import daikon.inv.*; 010import daikon.inv.unary.scalar.*; 011import daikon.split.*; 012import daikon.split.misc.*; 013import daikon.test.*; 014import java.io.ByteArrayOutputStream; 015import java.io.PrintStream; 016import java.lang.reflect.InvocationTargetException; 017import java.lang.reflect.Method; 018import java.util.ArrayList; 019import java.util.List; 020import junit.framework.*; 021import org.junit.Before; 022import org.junit.BeforeClass; 023import org.junit.Test; 024 025@SuppressWarnings({"nullness", "UnusedVariable"}) // testing code 026public class DiffTester { 027 028 private Diff diffSome; 029 private Diff diffAll; 030 031 private PptMap empty; 032 033 private PptMap ppts1; 034 private PptMap ppts2; 035 private PptMap ppts3; 036 private PptMap ppts4; 037 038 // ppts1 plus conditional program points 039 private PptMap pptsCond; 040 041 private PptMap invs1; 042 private PptMap invs2; 043 private PptMap invs3; 044 private PptMap imps1; 045 private PptMap imps2; 046 047 /** prepare for tests */ 048 @BeforeClass 049 public static void setUpClass() { 050 daikon.LogHelper.setupLogs(INFO); 051 FileIO.new_decl_format = true; 052 } 053 054 @Before 055 public void setUp() 056 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { 057 diffSome = new Diff(); 058 diffAll = new Diff(true); 059 060 empty = new PptMap(); 061 062 ppts1 = new PptMap(); 063 ppts1.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 064 ppts1.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 065 ppts1.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 066 067 ppts2 = new PptMap(); 068 ppts2.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 069 ppts2.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 070 071 // Permutation of ppts1 072 ppts3 = new PptMap(); 073 ppts3.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 074 ppts3.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 075 ppts3.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 076 077 { 078 ppts4 = new PptMap(); 079 ppts4.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 080 PptTopLevel ppt1 = newPptTopLevel("Foo.Bar(int):::EXIT19", new VarInfo[0]); 081 PptTopLevel ppt2 = newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]); 082 ppts4.add(ppt1); 083 ppts4.add(ppt2); 084 } 085 086 { 087 pptsCond = new PptMap(); 088 PptTopLevel ppt1 = newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]); 089 Splitter split = new ReturnTrueSplitter(); 090 PptSplitter ppt_split = new PptSplitter(ppt1, split); 091 ppt1.splitters = new ArrayList<PptSplitter>(); 092 ppt1.splitters.add(ppt_split); 093 pptsCond.add(ppt1); 094 pptsCond.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 095 pptsCond.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 096 } 097 098 // Invoke private method using reflection 099 Method mAddViews = PptTopLevel.class.getDeclaredMethod("addViews", new Class<?>[] {List.class}); 100 mAddViews.setAccessible(true); 101 102 { 103 invs1 = new PptMap(); 104 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 105 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 106 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 107 Invariant invx = LowerBound.get_proto().instantiate(slicex); 108 slicex.addInvariant(invx); 109 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 110 Invariant invy = LowerBound.get_proto().instantiate(slicey); 111 slicey.addInvariant(invy); 112 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 113 Invariant invz = LowerBound.get_proto().instantiate(slicez); 114 slicez.addInvariant(invz); 115 List<PptSlice> v = new ArrayList<>(); 116 v.add(slicex); 117 v.add(slicey); 118 v.add(slicez); 119 mAddViews.invoke(ppt, new Object[] {v}); 120 invs1.add(ppt); 121 } 122 123 { 124 // Permutation of invs1 125 invs2 = new PptMap(); 126 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 127 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 128 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 129 Invariant invy = LowerBound.get_proto().instantiate(slicey); 130 slicey.addInvariant(invy); 131 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 132 Invariant invx = LowerBound.get_proto().instantiate(slicex); 133 slicex.addInvariant(invx); 134 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 135 Invariant invz = LowerBound.get_proto().instantiate(slicez); 136 slicez.addInvariant(invz); 137 List<PptSlice> v = new ArrayList<>(); 138 v.add(slicey); 139 v.add(slicex); 140 v.add(slicez); 141 mAddViews.invoke(ppt, new Object[] {v}); 142 invs2.add(ppt); 143 } 144 145 { 146 invs3 = new PptMap(); 147 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 148 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 149 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 150 Invariant invx = LowerBound.get_proto().instantiate(slicex); 151 slicex.addInvariant(invx); 152 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 153 Invariant invy = UpperBound.get_proto().instantiate(slicey); 154 slicex.addInvariant(invy); 155 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 156 Invariant invz = LowerBound.get_proto().instantiate(slicez); 157 slicez.addInvariant(invz); 158 List<PptSlice> v = new ArrayList<>(); 159 v.add(slicex); 160 v.add(slicey); 161 v.add(slicez); 162 mAddViews.invoke(ppt, new Object[] {v}); 163 invs3.add(ppt); 164 } 165 166 { 167 // Ensure that Modulus is enabled 168 Configuration.getInstance().apply(daikon.inv.unary.scalar.Modulus.class, "enabled", "true"); 169 170 imps1 = new PptMap(); 171 VarInfo[] vars = {newIntVarInfo("x")}; 172 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 173 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 174 Invariant inv1 = LowerBound.get_proto().instantiate(slicex); 175 Invariant inv2 = Modulus.get_proto().instantiate(slicex); 176 Invariant inv3 = UpperBound.get_proto().instantiate(slicex); 177 Implication imp1 = Implication.makeImplication(ppt, inv1, inv2, false, inv1, inv2); 178 Implication imp2 = Implication.makeImplication(ppt, inv1, inv3, false, inv1, inv3); 179 Implication imp3 = Implication.makeImplication(ppt, inv2, inv1, false, inv2, inv1); 180 Implication imp4 = Implication.makeImplication(ppt, inv2, inv3, false, inv2, inv3); 181 Implication imp5 = Implication.makeImplication(ppt, inv3, inv1, false, inv3, inv1); 182 Implication imp6 = Implication.makeImplication(ppt, inv3, inv2, false, inv3, inv2); 183 imps1.add(ppt); 184 } 185 186 // Permutation of the nullary invariants in invs1 187 { 188 imps2 = new PptMap(); 189 VarInfo[] vars = {newIntVarInfo("x")}; 190 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 191 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 192 Invariant inv1 = LowerBound.get_proto().instantiate(slicex); 193 Invariant inv2 = Modulus.get_proto().instantiate(slicex); 194 Invariant inv3 = UpperBound.get_proto().instantiate(slicex); 195 Implication imp3 = Implication.makeImplication(ppt, inv2, inv1, false, inv2, inv1); 196 Implication imp2 = Implication.makeImplication(ppt, inv1, inv3, false, inv1, inv3); 197 Implication imp4 = Implication.makeImplication(ppt, inv2, inv3, false, inv2, inv3); 198 Implication imp5 = Implication.makeImplication(ppt, inv3, inv1, false, inv3, inv1); 199 Implication imp6 = Implication.makeImplication(ppt, inv3, inv2, false, inv3, inv2); 200 Implication imp1 = Implication.makeImplication(ppt, inv1, inv2, false, inv1, inv2); 201 imps2.add(ppt); 202 } 203 } 204 205 @SuppressWarnings("interning") 206 public static VarInfo newIntVarInfo(String name) { 207 return new VarInfo( 208 name, ProglangType.INT, ProglangType.INT, VarComparabilityNone.it, VarInfoAux.getDefault()); 209 } 210 211 @Test 212 public void testEmptyEmpty() { 213 RootNode diff = diffSome.diffPptMap(empty, empty); 214 RootNode ref = new RootNode(); 215 assertEquals(printTree(ref), printTree(diff)); 216 } 217 218 @Test 219 public void testEmptyPpts1() { 220 RootNode diff = diffSome.diffPptMap(empty, ppts1); 221 222 RootNode ref = new RootNode(); 223 PptNode node; 224 node = new PptNode(null, newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 225 ref.add(node); 226 node = new PptNode(null, newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 227 ref.add(node); 228 node = new PptNode(null, newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 229 ref.add(node); 230 231 assertEquals(printTree(ref), printTree(diff)); 232 } 233 234 @Test 235 public void testPpts1Empty() { 236 RootNode diff = diffSome.diffPptMap(ppts1, empty); 237 238 RootNode ref = new RootNode(); 239 PptNode node; 240 node = new PptNode(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), null); 241 ref.add(node); 242 node = new PptNode(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), null); 243 ref.add(node); 244 node = new PptNode(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), null); 245 ref.add(node); 246 247 assertEquals(printTree(ref), printTree(diff)); 248 } 249 250 @Test 251 public void testPpts1Ppts1() { 252 RootNode diff = diffSome.diffPptMap(ppts1, ppts1); 253 254 RootNode ref = new RootNode(); 255 PptNode node; 256 node = 257 new PptNode( 258 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), 259 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 260 ref.add(node); 261 node = 262 new PptNode( 263 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), 264 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 265 ref.add(node); 266 node = 267 new PptNode( 268 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), 269 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 270 ref.add(node); 271 272 assertEquals(printTree(ref), printTree(diff)); 273 } 274 275 @Test 276 public void testPpts1Ppts2() { 277 RootNode diff = diffSome.diffPptMap(ppts1, ppts2); 278 279 RootNode ref = new RootNode(); 280 PptNode node; 281 node = 282 new PptNode( 283 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), 284 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 285 ref.add(node); 286 node = 287 new PptNode( 288 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), 289 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 290 ref.add(node); 291 node = new PptNode(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), null); 292 ref.add(node); 293 294 assertEquals(printTree(ref), printTree(diff)); 295 } 296 297 @Test 298 public void testPpts1Ppts3() { 299 RootNode diff = diffSome.diffPptMap(ppts1, ppts3); 300 301 RootNode ref = new RootNode(); 302 PptNode node; 303 node = 304 new PptNode( 305 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), 306 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 307 ref.add(node); 308 node = 309 new PptNode( 310 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), 311 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 312 ref.add(node); 313 node = 314 new PptNode( 315 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), 316 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 317 ref.add(node); 318 319 assertEquals(printTree(ref), printTree(diff)); 320 } 321 322 @Test 323 public void testInvs1Empty() { 324 RootNode diff = diffSome.diffPptMap(invs1, empty); 325 326 RootNode ref = new RootNode(); 327 328 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 329 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 330 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 331 Invariant invx = LowerBound.get_proto().instantiate(slicex); 332 slicex.addInvariant(invx); 333 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 334 Invariant invy = LowerBound.get_proto().instantiate(slicey); 335 slicey.addInvariant(invy); 336 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 337 Invariant invz = LowerBound.get_proto().instantiate(slicez); 338 slicez.addInvariant(invz); 339 PptNode pptNode; 340 pptNode = new PptNode(ppt, null); 341 InvNode invNode; 342 invNode = new InvNode(invx, null); 343 pptNode.add(invNode); 344 invNode = new InvNode(invy, null); 345 pptNode.add(invNode); 346 invNode = new InvNode(invz, null); 347 pptNode.add(invNode); 348 ref.add(pptNode); 349 assertEquals(printTree(ref), printTree(diff)); 350 } 351 352 @Test 353 public void testInvs1Invs1() { 354 RootNode diff = diffSome.diffPptMap(invs1, invs1); 355 356 RootNode ref = new RootNode(); 357 358 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 359 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 360 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 361 Invariant invx = LowerBound.get_proto().instantiate(slicex); 362 slicex.addInvariant(invx); 363 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 364 Invariant invy = LowerBound.get_proto().instantiate(slicey); 365 slicey.addInvariant(invy); 366 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 367 Invariant invz = LowerBound.get_proto().instantiate(slicez); 368 slicez.addInvariant(invz); 369 370 PptNode pptNode; 371 pptNode = new PptNode(ppt, ppt); 372 InvNode invNode; 373 invNode = new InvNode(invx, invx); 374 pptNode.add(invNode); 375 invNode = new InvNode(invy, invy); 376 pptNode.add(invNode); 377 invNode = new InvNode(invz, invz); 378 pptNode.add(invNode); 379 ref.add(pptNode); 380 381 assertEquals(printTree(ref), printTree(diff)); 382 } 383 384 @Test 385 public void testInvs1Invs2() { 386 RootNode diff = diffSome.diffPptMap(invs1, invs2); 387 388 RootNode ref = new RootNode(); 389 390 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 391 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 392 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 393 Invariant invx = LowerBound.get_proto().instantiate(slicex); 394 slicex.addInvariant(invx); 395 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 396 Invariant invy = LowerBound.get_proto().instantiate(slicey); 397 slicey.addInvariant(invy); 398 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 399 Invariant invz = LowerBound.get_proto().instantiate(slicez); 400 slicez.addInvariant(invz); 401 402 PptNode pptNode; 403 pptNode = new PptNode(ppt, ppt); 404 InvNode invNode; 405 invNode = new InvNode(invx, invx); 406 pptNode.add(invNode); 407 invNode = new InvNode(invy, invy); 408 pptNode.add(invNode); 409 invNode = new InvNode(invz, invz); 410 pptNode.add(invNode); 411 ref.add(pptNode); 412 413 assertEquals(printTree(ref), printTree(diff)); 414 } 415 416 @Test 417 public void testInvs1Invs3() { 418 RootNode diff = diffSome.diffPptMap(invs1, invs3); 419 420 RootNode ref = new RootNode(); 421 422 VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")}; 423 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 424 PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]}); 425 Invariant invx = LowerBound.get_proto().instantiate(slicex); 426 PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]}); 427 Invariant invy1 = LowerBound.get_proto().instantiate(slicey); 428 Invariant invy2 = UpperBound.get_proto().instantiate(slicey); 429 PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]}); 430 Invariant invz = LowerBound.get_proto().instantiate(slicez); 431 432 PptNode pptNode; 433 pptNode = new PptNode(ppt, ppt); 434 InvNode invNode; 435 invNode = new InvNode(invx, invx); 436 pptNode.add(invNode); 437 invNode = new InvNode(invy1, null); 438 pptNode.add(invNode); 439 invNode = new InvNode(invz, invz); 440 pptNode.add(invNode); 441 invNode = new InvNode(null, invy2); 442 pptNode.add(invNode); 443 ref.add(pptNode); 444 445 assertEquals(printTree(ref), printTree(diff)); 446 } 447 448 @Test 449 public void testNullaryInvs() { 450 // executed for side effect 451 diffSome.diffPptMap(imps1, imps2); 452 } 453 454 @Test 455 public void testNonModulus() { 456 // Ensure that NonModulus is enabled 457 Configuration.getInstance().apply(daikon.inv.unary.scalar.NonModulus.class, "enabled", "true"); 458 459 PptMap map = new PptMap(); 460 VarInfo[] vars = {newIntVarInfo("x")}; 461 PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars); 462 PptSlice slice = new PptSlice1(ppt, vars); 463 Invariant inv = NonModulus.get_proto().instantiate(slice); 464 slice.addInvariant(inv); 465 map.add(ppt); 466 467 diffSome.diffPptMap(map, map); 468 } 469 470 // Runs diff on a PptMap containing a PptConditional, with 471 // examineAllPpts set to false. The PptConditional should be 472 // ignored. 473 @Test 474 public void testConditionalPptsFalse() { 475 RootNode diff = diffSome.diffPptMap(ppts1, pptsCond); 476 477 RootNode ref = new RootNode(); 478 PptNode node; 479 node = 480 new PptNode( 481 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), 482 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 483 ref.add(node); 484 node = 485 new PptNode( 486 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), 487 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 488 ref.add(node); 489 node = 490 new PptNode( 491 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), 492 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 493 ref.add(node); 494 495 assertEquals(printTree(ref), printTree(diff)); 496 } 497 498 // Runs diff on a PptMap containing a PptConditional, with 499 // examineAllPpts set to true. The PptConditional should be 500 // ignored. 501 @Test 502 public void testConditionalPptsTrue() { 503 RootNode diff = diffAll.diffPptMap(ppts1, pptsCond); 504 505 RootNode ref = new RootNode(); 506 PptNode node; 507 node = 508 new PptNode( 509 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), 510 newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0])); 511 ref.add(node); 512 node = 513 new PptNode( 514 null, 515 newPptTopLevel( 516 "Foo.Baa(int):::ENTER;condition=\"not(return == true)\"", new VarInfo[0])); 517 ref.add(node); 518 node = 519 new PptNode( 520 null, 521 newPptTopLevel("Foo.Baa(int):::ENTER;condition=\"return == true\"", new VarInfo[0])); 522 ref.add(node); 523 node = 524 new PptNode( 525 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), 526 newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0])); 527 ref.add(node); 528 node = 529 new PptNode( 530 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), 531 newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0])); 532 ref.add(node); 533 534 assertEquals(printTree(ref), printTree(diff)); 535 } 536 537 private static String printTree(RootNode root) { 538 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 539 PrintStream ps = new PrintStream(baos); 540 PrintAllVisitor v = new PrintAllVisitor(ps, false, true); 541 root.accept(v); 542 @SuppressWarnings("DefaultCharset") // toString(Charset) was introduced in Java 10 543 String result = baos.toString(); 544 return result; 545 } 546 547 /////////////////////////////////////////////////////////////////////////// 548 /// Helper functions 549 /// 550 551 static PptTopLevel newPptTopLevel(String pptname, VarInfo[] vars) { 552 return Common.makePptTopLevel(pptname, vars); 553 } 554}