1 /* 2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.ByteArrayOutputStream; 25 import java.io.PrintStream; 26 import java.io.StringWriter; 27 import java.lang.reflect.Method; 28 import java.nio.file.Path; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.Collection; 32 import java.util.Collections; 33 import java.util.HashMap; 34 import java.util.LinkedHashMap; 35 import java.util.LinkedHashSet; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Set; 39 import java.util.TreeMap; 40 import java.util.function.Consumer; 41 import java.util.function.Predicate; 42 import java.util.function.Supplier; 43 import java.util.stream.Collectors; 44 import java.util.stream.Stream; 45 46 import javax.tools.Diagnostic; 47 48 import jdk.jshell.EvalException; 49 import jdk.jshell.JShell; 50 import jdk.jshell.JShell.Subscription; 51 import jdk.jshell.Snippet; 52 import jdk.jshell.DeclarationSnippet; 53 import jdk.jshell.ExpressionSnippet; 54 import jdk.jshell.ImportSnippet; 55 import jdk.jshell.Snippet.Kind; 56 import jdk.jshell.MethodSnippet; 57 import jdk.jshell.PersistentSnippet; 58 import jdk.jshell.Snippet.Status; 59 import jdk.jshell.Snippet.SubKind; 60 import jdk.jshell.TypeDeclSnippet; 61 import jdk.jshell.VarSnippet; 62 import jdk.jshell.SnippetEvent; 63 import jdk.jshell.SourceCodeAnalysis; 64 import jdk.jshell.SourceCodeAnalysis.CompletionInfo; 65 import jdk.jshell.SourceCodeAnalysis.Completeness; 66 import jdk.jshell.SourceCodeAnalysis.QualifiedNames; 67 import jdk.jshell.SourceCodeAnalysis.Suggestion; 68 import jdk.jshell.UnresolvedReferenceException; 69 import org.testng.annotations.AfterMethod; 70 import org.testng.annotations.BeforeMethod; 71 72 import jdk.jshell.Diag; 73 import static jdk.jshell.Snippet.Status.*; 74 import static org.testng.Assert.*; 75 import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND; 76 import jdk.jshell.spi.ExecutionControl; 77 78 public class KullaTesting { 79 80 public static final String IGNORE_VALUE = "<ignore-value>"; 81 public static final Class<? extends Throwable> IGNORE_EXCEPTION = (new Throwable() {}).getClass(); 82 public static final Snippet MAIN_SNIPPET; 83 84 private SourceCodeAnalysis analysis = null; 85 private JShell state = null; 86 private TestingInputStream inStream = null; 87 private ByteArrayOutputStream outStream = null; 88 private ByteArrayOutputStream errStream = null; 89 90 private Map<String, Snippet> idToSnippet = new LinkedHashMap<>(); 91 private Set<Snippet> allSnippets = new LinkedHashSet<>(); 92 private List<String> classpath; 93 94 static { 95 JShell js = JShell.create(); 96 MAIN_SNIPPET = js.eval("MAIN_SNIPPET").get(0).snippet(); 97 js.close(); 98 assertTrue(MAIN_SNIPPET != null, "Bad MAIN_SNIPPET set-up -- must not be null"); 99 } 100 101 public enum DiagCheck { 102 DIAG_OK, 103 DIAG_WARNING, 104 DIAG_ERROR, 105 DIAG_IGNORE 106 } 107 108 public void setInput(String s) { 109 inStream.setInput(s); 110 } 111 112 public String getOutput() { 113 String s = outStream.toString(); 114 outStream.reset(); 115 return s; 116 } 117 118 public String getErrorOutput() { 119 String s = errStream.toString(); 120 errStream.reset(); 121 return s; 122 } 123 124 /** 125 * @return the analysis 126 */ 127 public SourceCodeAnalysis getAnalysis() { 128 if (analysis == null) { 129 analysis = state.sourceCodeAnalysis(); 130 } 131 return analysis; 132 } 133 134 /** 135 * @return the state 136 */ 137 public JShell getState() { 138 return state; 139 } 140 141 public List<Snippet> getActiveKeys() { 142 return allSnippets.stream() 143 .filter(k -> getState().status(k).isActive()) 144 .collect(Collectors.toList()); 145 } 146 147 public void addToClasspath(String path) { 148 classpath.add(path); 149 getState().addToClasspath(path); 150 } 151 152 public void addToClasspath(Path path) { 153 addToClasspath(path.toString()); 154 } 155 156 @BeforeMethod 157 public void setUp() { 158 setUp(b -> {}); 159 } 160 161 public void setUp(ExecutionControl ec) { 162 setUp(b -> b.executionEngine(ec)); 163 } 164 165 public void setUp(Consumer<JShell.Builder> bc) { 166 inStream = new TestingInputStream(); 167 outStream = new ByteArrayOutputStream(); 168 errStream = new ByteArrayOutputStream(); 169 JShell.Builder builder = JShell.builder() 170 .in(inStream) 171 .out(new PrintStream(outStream)) 172 .err(new PrintStream(errStream)); 173 bc.accept(builder); 174 state = builder.build(); 175 allSnippets = new LinkedHashSet<>(); 176 idToSnippet = new LinkedHashMap<>(); 177 classpath = new ArrayList<>(); 178 } 179 180 @AfterMethod 181 public void tearDown() { 182 if (state != null) state.close(); 183 state = null; 184 analysis = null; 185 allSnippets = null; 186 idToSnippet = null; 187 classpath = null; 188 } 189 190 public List<String> assertUnresolvedDependencies(DeclarationSnippet key, int unresolvedSize) { 191 List<String> unresolved = getState().unresolvedDependencies(key); 192 assertEquals(unresolved.size(), unresolvedSize, "Input: " + key.source() + ", checking unresolved: "); 193 return unresolved; 194 } 195 196 public DeclarationSnippet assertUnresolvedDependencies1(DeclarationSnippet key, Status status, String name) { 197 List<String> unresolved = assertUnresolvedDependencies(key, 1); 198 String input = key.source(); 199 assertEquals(unresolved.size(), 1, "Given input: " + input + ", checking unresolved"); 200 assertEquals(unresolved.get(0), name, "Given input: " + input + ", checking unresolved: "); 201 assertEquals(getState().status(key), status, "Given input: " + input + ", checking status: "); 202 return key; 203 } 204 205 public DeclarationSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) { 206 List<SnippetEvent> events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); 207 SnippetEvent ste = events.get(0); 208 DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); 209 assertEquals(sn.name(), name, "Given input: " + input + ", checking name"); 210 assertEquals(getState().unresolvedDependencies(sn).size(), unresolvedSize, "Given input: " + input + ", checking unresolved"); 211 assertEquals(getState().diagnostics(sn).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics"); 212 return sn; 213 } 214 215 public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) { 216 Snippet key = key(assertEval(input, IGNORE_VALUE, mainInfo, updates)); 217 String source = key.source(); 218 assertEquals(source, input, "Key \"" + input + "\" source mismatch, got: " + source + ", expected: " + input); 219 SubKind subkind = key.subKind(); 220 assertEquals(subkind, expectedSubKind, "Key \"" + input + "\" subkind mismatch, got: " 221 + subkind + ", expected: " + expectedSubKind); 222 assertEquals(subkind.isExecutable(), isExecutable, "Key \"" + input + "\", expected isExecutable: " 223 + isExecutable + ", got: " + subkind.isExecutable()); 224 Snippet.Kind expectedKind = getKind(key); 225 assertEquals(key.kind(), expectedKind, "Checking kind: "); 226 assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); 227 return key; 228 } 229 230 private Kind getKind(Snippet key) { 231 SubKind expectedSubKind = key.subKind(); 232 Kind expectedKind; 233 switch (expectedSubKind) { 234 case SINGLE_TYPE_IMPORT_SUBKIND: 235 case SINGLE_STATIC_IMPORT_SUBKIND: 236 case TYPE_IMPORT_ON_DEMAND_SUBKIND: 237 case STATIC_IMPORT_ON_DEMAND_SUBKIND: 238 expectedKind = Kind.IMPORT; 239 break; 240 case CLASS_SUBKIND: 241 case INTERFACE_SUBKIND: 242 case ENUM_SUBKIND: 243 case ANNOTATION_TYPE_SUBKIND: 244 expectedKind = Kind.TYPE_DECL; 245 break; 246 case METHOD_SUBKIND: 247 expectedKind = Kind.METHOD; 248 break; 249 case VAR_DECLARATION_SUBKIND: 250 case TEMP_VAR_EXPRESSION_SUBKIND: 251 case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: 252 expectedKind = Kind.VAR; 253 break; 254 case VAR_VALUE_SUBKIND: 255 case ASSIGNMENT_SUBKIND: 256 expectedKind = Kind.EXPRESSION; 257 break; 258 case STATEMENT_SUBKIND: 259 expectedKind = Kind.STATEMENT; 260 break; 261 case UNKNOWN_SUBKIND: 262 expectedKind = Kind.ERRONEOUS; 263 break; 264 default: 265 throw new AssertionError("Unsupported key: " + key.getClass().getCanonicalName()); 266 } 267 return expectedKind; 268 } 269 270 public ImportSnippet assertImportKeyMatch(String input, String name, SubKind subkind, STEInfo mainInfo, STEInfo... updates) { 271 Snippet key = assertKeyMatch(input, false, subkind, mainInfo, updates); 272 273 assertTrue(key instanceof ImportSnippet, "Expected an ImportKey, got: " + key.getClass().getName()); 274 ImportSnippet importKey = (ImportSnippet) key; 275 assertEquals(importKey.name(), name, "Input \"" + input + 276 "\" name mismatch, got: " + importKey.name() + ", expected: " + name); 277 assertEquals(importKey.kind(), Kind.IMPORT, "Checking kind: "); 278 return importKey; 279 } 280 281 public DeclarationSnippet assertDeclarationKeyMatch(String input, boolean isExecutable, String name, SubKind subkind, STEInfo mainInfo, STEInfo... updates) { 282 Snippet key = assertKeyMatch(input, isExecutable, subkind, mainInfo, updates); 283 284 assertTrue(key instanceof DeclarationSnippet, "Expected a DeclarationKey, got: " + key.getClass().getName()); 285 DeclarationSnippet declKey = (DeclarationSnippet) key; 286 assertEquals(declKey.name(), name, "Input \"" + input + 287 "\" name mismatch, got: " + declKey.name() + ", expected: " + name); 288 return declKey; 289 } 290 291 public VarSnippet assertVarKeyMatch(String input, boolean isExecutable, String name, SubKind kind, String typeName, STEInfo mainInfo, STEInfo... updates) { 292 Snippet sn = assertDeclarationKeyMatch(input, isExecutable, name, kind, mainInfo, updates); 293 assertTrue(sn instanceof VarSnippet, "Expected a VarKey, got: " + sn.getClass().getName()); 294 VarSnippet variableKey = (VarSnippet) sn; 295 String signature = variableKey.typeName(); 296 assertEquals(signature, typeName, "Key \"" + input + 297 "\" typeName mismatch, got: " + signature + ", expected: " + typeName); 298 assertEquals(variableKey.kind(), Kind.VAR, "Checking kind: "); 299 return variableKey; 300 } 301 302 public void assertExpressionKeyMatch(String input, String name, SubKind kind, String typeName) { 303 Snippet key = assertKeyMatch(input, true, kind, added(VALID)); 304 assertTrue(key instanceof ExpressionSnippet, "Expected a ExpressionKey, got: " + key.getClass().getName()); 305 ExpressionSnippet exprKey = (ExpressionSnippet) key; 306 assertEquals(exprKey.name(), name, "Input \"" + input + 307 "\" name mismatch, got: " + exprKey.name() + ", expected: " + name); 308 assertEquals(exprKey.typeName(), typeName, "Key \"" + input + 309 "\" typeName mismatch, got: " + exprKey.typeName() + ", expected: " + typeName); 310 assertEquals(exprKey.kind(), Kind.EXPRESSION, "Checking kind: "); 311 } 312 313 // For expressions throwing an EvalException 314 public SnippetEvent assertEvalException(String input) { 315 List<SnippetEvent> events = assertEval(input, null, EvalException.class, 316 DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); 317 return events.get(0); 318 } 319 320 321 public List<SnippetEvent> assertEvalFail(String input) { 322 return assertEval(input, null, null, 323 DiagCheck.DIAG_ERROR, DiagCheck.DIAG_IGNORE, added(REJECTED)); 324 } 325 326 public List<SnippetEvent> assertEval(String input) { 327 return assertEval(input, IGNORE_VALUE, null, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, added(VALID)); 328 } 329 330 public List<SnippetEvent> assertEval(String input, String value) { 331 return assertEval(input, value, null, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, added(VALID)); 332 } 333 334 public List<SnippetEvent> assertEval(String input, STEInfo mainInfo, STEInfo... updates) { 335 return assertEval(input, IGNORE_VALUE, null, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, mainInfo, updates); 336 } 337 338 public List<SnippetEvent> assertEval(String input, String value, 339 STEInfo mainInfo, STEInfo... updates) { 340 return assertEval(input, value, null, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, mainInfo, updates); 341 } 342 343 public List<SnippetEvent> assertEval(String input, DiagCheck diagMain, DiagCheck diagUpdates) { 344 return assertEval(input, IGNORE_VALUE, null, diagMain, diagUpdates, added(VALID)); 345 } 346 347 public List<SnippetEvent> assertEval(String input, DiagCheck diagMain, DiagCheck diagUpdates, 348 STEInfo mainInfo, STEInfo... updates) { 349 return assertEval(input, IGNORE_VALUE, null, diagMain, diagUpdates, mainInfo, updates); 350 } 351 352 public List<SnippetEvent> assertEval(String input, 353 String value, Class<? extends Throwable> exceptionClass, 354 DiagCheck diagMain, DiagCheck diagUpdates, 355 STEInfo mainInfo, STEInfo... updates) { 356 return assertEval(input, diagMain, diagUpdates, new EventChain(mainInfo, value, exceptionClass, updates)); 357 } 358 359 // Use this directly or usually indirectly for all non-empty calls to eval() 360 public List<SnippetEvent> assertEval(String input, 361 DiagCheck diagMain, DiagCheck diagUpdates, EventChain... eventChains) { 362 return checkEvents(() -> getState().eval(input), "eval(" + input + ")", diagMain, diagUpdates, eventChains); 363 } 364 365 private Map<Snippet, Snippet> closure(List<SnippetEvent> events) { 366 Map<Snippet, Snippet> transitions = new HashMap<>(); 367 for (SnippetEvent event : events) { 368 transitions.put(event.snippet(), event.causeSnippet()); 369 } 370 Map<Snippet, Snippet> causeSnippets = new HashMap<>(); 371 for (Map.Entry<Snippet, Snippet> entry : transitions.entrySet()) { 372 Snippet snippet = entry.getKey(); 373 Snippet cause = getInitialCause(transitions, entry.getValue()); 374 causeSnippets.put(snippet, cause); 375 } 376 return causeSnippets; 377 } 378 379 private Snippet getInitialCause(Map<Snippet, Snippet> transitions, Snippet snippet) { 380 Snippet result; 381 while ((result = transitions.get(snippet)) != null) { 382 snippet = result; 383 } 384 return snippet; 385 } 386 387 private Map<Snippet, List<SnippetEvent>> groupByCauseSnippet(List<SnippetEvent> events) { 388 Map<Snippet, List<SnippetEvent>> map = new TreeMap<>((a, b) -> a.id().compareTo(b.id())); 389 for (SnippetEvent event : events) { 390 if (event == null) { 391 throw new InternalError("null event found in " + events); 392 } 393 if (event.snippet() == null) { 394 throw new InternalError("null event Snippet found in " + events); 395 } 396 if (event.snippet().id() == null) { 397 throw new InternalError("null event Snippet id() found in " + events); 398 } 399 } 400 for (SnippetEvent event : events) { 401 if (event.causeSnippet() == null) { 402 map.computeIfAbsent(event.snippet(), ($) -> new ArrayList<>()).add(event); 403 } 404 } 405 Map<Snippet, Snippet> causeSnippets = closure(events); 406 for (SnippetEvent event : events) { 407 Snippet causeSnippet = causeSnippets.get(event.snippet()); 408 if (causeSnippet != null) { 409 map.get(causeSnippet).add(event); 410 } 411 } 412 for (Map.Entry<Snippet, List<SnippetEvent>> entry : map.entrySet()) { 413 Collections.sort(entry.getValue(), 414 (a, b) -> a.causeSnippet() == null 415 ? -1 : b.causeSnippet() == null 416 ? 1 : a.snippet().id().compareTo(b.snippet().id())); 417 } 418 return map; 419 } 420 421 private List<STEInfo> getInfos(EventChain... eventChains) { 422 List<STEInfo> list = new ArrayList<>(); 423 for (EventChain i : eventChains) { 424 list.add(i.mainInfo); 425 Collections.addAll(list, i.updates); 426 } 427 return list; 428 } 429 430 private List<SnippetEvent> checkEvents(Supplier<List<SnippetEvent>> toTest, 431 String descriptor, 432 DiagCheck diagMain, DiagCheck diagUpdates, 433 EventChain... eventChains) { 434 List<SnippetEvent> dispatched = new ArrayList<>(); 435 Subscription token = getState().onSnippetEvent(kse -> { 436 if (dispatched.size() > 0 && dispatched.get(dispatched.size() - 1) == null) { 437 throw new RuntimeException("dispatch event after done"); 438 } 439 dispatched.add(kse); 440 }); 441 List<SnippetEvent> events = toTest.get(); 442 getState().unsubscribe(token); 443 assertEquals(dispatched.size(), events.size(), "dispatched event size not the same as event size"); 444 for (int i = events.size() - 1; i >= 0; --i) { 445 assertEquals(dispatched.get(i), events.get(i), "Event element " + i + " does not match"); 446 } 447 dispatched.add(null); // mark end of dispatchs 448 449 for (SnippetEvent evt : events) { 450 assertTrue(evt.snippet() != null, "key must never be null, but it was for: " + descriptor); 451 assertTrue(evt.previousStatus() != null, "previousStatus must never be null, but it was for: " + descriptor); 452 assertTrue(evt.status() != null, "status must never be null, but it was for: " + descriptor); 453 assertTrue(evt.status() != NONEXISTENT, "status must not be NONEXISTENT: " + descriptor); 454 if (evt.previousStatus() != NONEXISTENT) { 455 Snippet old = idToSnippet.get(evt.snippet().id()); 456 if (old != null) { 457 switch (evt.status()) { 458 case DROPPED: 459 assertEquals(old, evt.snippet(), 460 "Drop: Old snippet must be what is dropped -- input: " + descriptor); 461 break; 462 case OVERWRITTEN: 463 assertEquals(old, evt.snippet(), 464 "Overwrite: Old snippet (" + old 465 + ") must be what is overwritten -- input: " 466 + descriptor + " -- " + evt); 467 break; 468 default: 469 if (evt.causeSnippet() == null) { 470 // New source 471 assertNotEquals(old, evt.snippet(), 472 "New source: Old snippet must be different from the replacing -- input: " 473 + descriptor); 474 } else { 475 // An update (key Overwrite??) 476 assertEquals(old, evt.snippet(), 477 "Update: Old snippet must be equal to the replacing -- input: " 478 + descriptor); 479 } 480 break; 481 } 482 } 483 } 484 } 485 for (SnippetEvent evt : events) { 486 if (evt.causeSnippet() == null && evt.status() != DROPPED) { 487 allSnippets.add(evt.snippet()); 488 idToSnippet.put(evt.snippet().id(), evt.snippet()); 489 } 490 } 491 assertTrue(events.size() >= 1, "Expected at least one event, got none."); 492 List<STEInfo> all = getInfos(eventChains); 493 if (events.size() != all.size()) { 494 StringBuilder sb = new StringBuilder(); 495 sb.append("Got events --\n"); 496 for (SnippetEvent evt : events) { 497 sb.append(" key: ").append(evt.snippet()); 498 sb.append(" before: ").append(evt.previousStatus()); 499 sb.append(" status: ").append(evt.status()); 500 sb.append(" isSignatureChange: ").append(evt.isSignatureChange()); 501 sb.append(" cause: "); 502 if (evt.causeSnippet() == null) { 503 sb.append("direct"); 504 } else { 505 sb.append(evt.causeSnippet()); 506 } 507 sb.append("\n"); 508 } 509 sb.append("Expected ").append(all.size()); 510 sb.append(" events, got: ").append(events.size()); 511 fail(sb.toString()); 512 } 513 514 int impactId = 0; 515 Map<Snippet, List<SnippetEvent>> groupedEvents = groupByCauseSnippet(events); 516 assertEquals(groupedEvents.size(), eventChains.length, "Number of main events"); 517 for (Map.Entry<Snippet, List<SnippetEvent>> entry : groupedEvents.entrySet()) { 518 EventChain eventChain = eventChains[impactId++]; 519 SnippetEvent main = entry.getValue().get(0); 520 Snippet mainKey = main.snippet(); 521 if (eventChain.mainInfo != null) { 522 eventChain.mainInfo.assertMatch(entry.getValue().get(0), mainKey); 523 if (eventChain.updates.length > 0) { 524 if (eventChain.updates.length == 1) { 525 eventChain.updates[0].assertMatch(entry.getValue().get(1), mainKey); 526 } else { 527 Arrays.sort(eventChain.updates, (a, b) -> ((a.snippet() == MAIN_SNIPPET) 528 ? mainKey 529 : a.snippet()).id().compareTo(b.snippet().id())); 530 List<SnippetEvent> updateEvents = new ArrayList<>(entry.getValue().subList(1, entry.getValue().size())); 531 int idx = 0; 532 for (SnippetEvent ste : updateEvents) { 533 eventChain.updates[idx++].assertMatch(ste, mainKey); 534 } 535 } 536 } 537 } 538 if (((Object) eventChain.value) != IGNORE_VALUE) { 539 assertEquals(main.value(), eventChain.value, "Expected execution value of: " + eventChain.value + 540 ", but got: " + main.value()); 541 } 542 if (eventChain.exceptionClass != IGNORE_EXCEPTION) { 543 if (main.exception() == null) { 544 assertEquals(eventChain.exceptionClass, null, "Expected an exception of class " 545 + eventChain.exceptionClass + " got no exception"); 546 } else if (eventChain.exceptionClass == null) { 547 fail("Expected no exception but got " + main.exception().toString()); 548 } else { 549 assertTrue(eventChain.exceptionClass.isInstance(main.exception()), 550 "Expected an exception of class " + eventChain.exceptionClass + 551 " got: " + main.exception().toString()); 552 } 553 } 554 List<Diag> diagnostics = getState().diagnostics(mainKey); 555 switch (diagMain) { 556 case DIAG_OK: 557 assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); 558 break; 559 case DIAG_WARNING: 560 assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); 561 break; 562 case DIAG_ERROR: 563 assertTrue(hasFatalError(diagnostics), "Expected errors, got: " + diagnosticsToString(diagnostics)); 564 break; 565 } 566 if (eventChain.mainInfo != null) { 567 for (STEInfo ste : eventChain.updates) { 568 diagnostics = getState().diagnostics(ste.snippet()); 569 switch (diagUpdates) { 570 case DIAG_OK: 571 assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); 572 break; 573 case DIAG_WARNING: 574 assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); 575 break; 576 } 577 } 578 } 579 } 580 return events; 581 } 582 583 // Use this for all EMPTY calls to eval() 584 public void assertEvalEmpty(String input) { 585 List<SnippetEvent> events = getState().eval(input); 586 assertEquals(events.size(), 0, "Expected no events, got: " + events.size()); 587 } 588 589 public VarSnippet varKey(List<SnippetEvent> events) { 590 Snippet key = key(events); 591 assertTrue(key instanceof VarSnippet, "Expected a VariableKey, got: " + key); 592 return (VarSnippet) key; 593 } 594 595 public MethodSnippet methodKey(List<SnippetEvent> events) { 596 Snippet key = key(events); 597 assertTrue(key instanceof MethodSnippet, "Expected a MethodKey, got: " + key); 598 return (MethodSnippet) key; 599 } 600 601 public TypeDeclSnippet classKey(List<SnippetEvent> events) { 602 Snippet key = key(events); 603 assertTrue(key instanceof TypeDeclSnippet, "Expected a ClassKey, got: " + key); 604 return (TypeDeclSnippet) key; 605 } 606 607 public ImportSnippet importKey(List<SnippetEvent> events) { 608 Snippet key = key(events); 609 assertTrue(key instanceof ImportSnippet, "Expected a ImportKey, got: " + key); 610 return (ImportSnippet) key; 611 } 612 613 public Snippet key(List<SnippetEvent> events) { 614 assertTrue(events.size() >= 1, "Expected at least one event, got none."); 615 return events.get(0).snippet(); 616 } 617 618 public void assertVarValue(Snippet key, String expected) { 619 String value = state.varValue((VarSnippet) key); 620 assertEquals(value, expected, "Expected var value of: " + expected + ", but got: " + value); 621 } 622 623 public Snippet assertDeclareFail(String input, String expectedErrorCode) { 624 return assertDeclareFail(input, expectedErrorCode, added(REJECTED)); 625 } 626 627 public Snippet assertDeclareFail(String input, String expectedErrorCode, 628 STEInfo mainInfo, STEInfo... updates) { 629 return assertDeclareFail(input, 630 new ExpectedDiagnostic(expectedErrorCode, -1, -1, -1, -1, -1, Diagnostic.Kind.ERROR), 631 mainInfo, updates); 632 } 633 634 public Snippet assertDeclareFail(String input, ExpectedDiagnostic expectedDiagnostic) { 635 return assertDeclareFail(input, expectedDiagnostic, added(REJECTED)); 636 } 637 638 public Snippet assertDeclareFail(String input, ExpectedDiagnostic expectedDiagnostic, 639 STEInfo mainInfo, STEInfo... updates) { 640 List<SnippetEvent> events = assertEval(input, null, null, 641 DiagCheck.DIAG_ERROR, DiagCheck.DIAG_IGNORE, mainInfo, updates); 642 SnippetEvent e = events.get(0); 643 Snippet key = e.snippet(); 644 assertEquals(getState().status(key), REJECTED); 645 List<Diag> diagnostics = getState().diagnostics(e.snippet()); 646 assertTrue(diagnostics.size() > 0, "Expected diagnostics, got none"); 647 assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); 648 assertTrue(key != null, "key must never be null, but it was for: " + input); 649 return key; 650 } 651 652 public Snippet assertDeclareWarn1(String input, String expectedErrorCode) { 653 return assertDeclareWarn1(input, new ExpectedDiagnostic(expectedErrorCode, -1, -1, -1, -1, -1, Diagnostic.Kind.WARNING)); 654 } 655 656 public Snippet assertDeclareWarn1(String input, ExpectedDiagnostic expectedDiagnostic) { 657 return assertDeclareWarn1(input, expectedDiagnostic, added(VALID)); 658 } 659 660 public Snippet assertDeclareWarn1(String input, ExpectedDiagnostic expectedDiagnostic, STEInfo mainInfo, STEInfo... updates) { 661 List<SnippetEvent> events = assertEval(input, IGNORE_VALUE, null, 662 DiagCheck.DIAG_WARNING, DiagCheck.DIAG_IGNORE, mainInfo, updates); 663 SnippetEvent e = events.get(0); 664 List<Diag> diagnostics = getState().diagnostics(e.snippet()); 665 if (expectedDiagnostic != null) assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); 666 return e.snippet(); 667 } 668 669 private void assertDiagnostic(String input, Diag diagnostic, ExpectedDiagnostic expectedDiagnostic) { 670 if (expectedDiagnostic != null) expectedDiagnostic.assertDiagnostic(diagnostic); 671 // assertEquals(diagnostic.getSource(), input, "Diagnostic source"); 672 } 673 674 public void assertTypeDeclSnippet(TypeDeclSnippet type, String expectedName, 675 Status expectedStatus, SubKind expectedSubKind, 676 int unressz, int othersz) { 677 assertDeclarationSnippet(type, expectedName, expectedStatus, 678 expectedSubKind, unressz, othersz); 679 } 680 681 public void assertMethodDeclSnippet(MethodSnippet method, 682 String expectedName, String expectedSignature, 683 Status expectedStatus, int unressz, int othersz) { 684 assertDeclarationSnippet(method, expectedName, expectedStatus, 685 METHOD_SUBKIND, unressz, othersz); 686 String signature = method.signature(); 687 assertEquals(signature, expectedSignature, 688 "Expected " + method.source() + " to have the name: " + 689 expectedSignature + ", got: " + signature); 690 } 691 692 public void assertVariableDeclSnippet(VarSnippet var, 693 String expectedName, String expectedTypeName, 694 Status expectedStatus, SubKind expectedSubKind, 695 int unressz, int othersz) { 696 assertDeclarationSnippet(var, expectedName, expectedStatus, 697 expectedSubKind, unressz, othersz); 698 String signature = var.typeName(); 699 assertEquals(signature, expectedTypeName, 700 "Expected " + var.source() + " to have the name: " + 701 expectedTypeName + ", got: " + signature); 702 } 703 704 public void assertDeclarationSnippet(DeclarationSnippet declarationKey, 705 String expectedName, 706 Status expectedStatus, SubKind expectedSubKind, 707 int unressz, int othersz) { 708 assertKey(declarationKey, expectedStatus, expectedSubKind); 709 String source = declarationKey.source(); 710 assertEquals(declarationKey.name(), expectedName, 711 "Expected " + source + " to have the name: " + expectedName + ", got: " + declarationKey.name()); 712 List<String> unresolved = getState().unresolvedDependencies(declarationKey); 713 assertEquals(unresolved.size(), unressz, "Expected " + source + " to have " + unressz 714 + " unresolved symbols, got: " + unresolved.size()); 715 List<Diag> otherCorralledErrors = getState().diagnostics(declarationKey); 716 assertEquals(otherCorralledErrors.size(), othersz, "Expected " + source + " to have " + othersz 717 + " other errors, got: " + otherCorralledErrors.size()); 718 } 719 720 public void assertKey(Snippet key, Status expectedStatus, SubKind expectedSubKind) { 721 String source = key.source(); 722 SubKind actualSubKind = key.subKind(); 723 assertEquals(actualSubKind, expectedSubKind, 724 "Expected " + source + " to have the subkind: " + expectedSubKind + ", got: " + actualSubKind); 725 Status status = getState().status(key); 726 assertEquals(status, expectedStatus, "Expected " + source + " to be " 727 + expectedStatus + ", but it is " + status); 728 Snippet.Kind expectedKind = getKind(key); 729 assertEquals(key.kind(), expectedKind, "Checking kind: "); 730 assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); 731 } 732 733 public void assertDrop(PersistentSnippet key, STEInfo mainInfo, STEInfo... updates) { 734 assertDrop(key, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, mainInfo, updates); 735 } 736 737 public void assertDrop(PersistentSnippet key, DiagCheck diagMain, DiagCheck diagUpdates, STEInfo mainInfo, STEInfo... updates) { 738 assertDrop(key, diagMain, diagUpdates, new EventChain(mainInfo, null, null, updates)); 739 } 740 741 public void assertDrop(PersistentSnippet key, DiagCheck diagMain, DiagCheck diagUpdates, EventChain... eventChains) { 742 checkEvents(() -> getState().drop(key), "drop(" + key + ")", diagMain, diagUpdates, eventChains); 743 } 744 745 public void assertAnalyze(String input, String source, String remaining, boolean isComplete) { 746 assertAnalyze(input, null, source, remaining, isComplete); 747 } 748 749 public void assertAnalyze(String input, Completeness status, String source) { 750 assertAnalyze(input, status, source, null, null); 751 } 752 753 public void assertAnalyze(String input, Completeness status, String source, String remaining, Boolean isComplete) { 754 CompletionInfo ci = getAnalysis().analyzeCompletion(input); 755 if (status != null) assertEquals(ci.completeness(), status, "Input : " + input + ", status: "); 756 if (source != null) assertEquals(ci.source(), source, "Input : " + input + ", source: "); 757 if (remaining != null) assertEquals(ci.remaining(), remaining, "Input : " + input + ", remaining: "); 758 if (isComplete != null) { 759 boolean isExpectedComplete = isComplete; 760 assertEquals(ci.completeness().isComplete(), isExpectedComplete, "Input : " + input + ", isComplete: "); 761 } 762 } 763 764 public void assertNumberOfActiveVariables(int cnt) { 765 Collection<VarSnippet> variables = getState().variables(); 766 assertEquals(variables.size(), cnt, "Variables : " + variables); 767 } 768 769 public void assertNumberOfActiveMethods(int cnt) { 770 Collection<MethodSnippet> methods = getState().methods(); 771 assertEquals(methods.size(), cnt, "Methods : " + methods); 772 } 773 774 public void assertNumberOfActiveClasses(int cnt) { 775 Collection<TypeDeclSnippet> classes = getState().types(); 776 assertEquals(classes.size(), cnt, "Classes : " + classes); 777 } 778 779 public void assertMembers(Collection<? extends Snippet> members, Set<MemberInfo> expected) { 780 assertEquals(members.size(), expected.size(), "Expected : " + expected + ", actual : " + members); 781 assertEquals(members.stream() 782 .map(this::getMemberInfo) 783 .collect(Collectors.toSet()), 784 expected); 785 } 786 787 public void assertKeys(MemberInfo... expected) { 788 int index = 0; 789 List<Snippet> snippets = getState().snippets(); 790 assertEquals(allSnippets.size(), snippets.size()); 791 for (Snippet sn : snippets) { 792 if (sn.kind().isPersistent() && getState().status(sn).isActive()) { 793 MemberInfo actual = getMemberInfo(sn); 794 MemberInfo exp = expected[index]; 795 assertEquals(actual, exp, String.format("Difference in #%d. Expected: %s, actual: %s", 796 index, exp, actual)); 797 ++index; 798 } 799 } 800 } 801 802 public void assertActiveKeys() { 803 Collection<Snippet> expected = getActiveKeys(); 804 assertActiveKeys(expected.toArray(new Snippet[expected.size()])); 805 } 806 807 public void assertActiveKeys(Snippet... expected) { 808 int index = 0; 809 for (Snippet key : getState().snippets()) { 810 if (state.status(key).isActive()) { 811 assertEquals(expected[index], key, String.format("Difference in #%d. Expected: %s, actual: %s", index, key, expected[index])); 812 ++index; 813 } 814 } 815 } 816 817 private List<Snippet> filterDeclaredKeys(Predicate<Snippet> p) { 818 return getActiveKeys().stream() 819 .filter(p) 820 .collect(Collectors.toList()); 821 } 822 823 public void assertVariables() { 824 assertEquals(getState().variables(), filterDeclaredKeys((key) -> key instanceof VarSnippet), "Variables"); 825 } 826 827 public void assertMethods() { 828 assertEquals(getState().methods(), filterDeclaredKeys((key) -> key instanceof MethodSnippet), "Methods"); 829 } 830 831 public void assertClasses() { 832 assertEquals(getState().types(), filterDeclaredKeys((key) -> key instanceof TypeDeclSnippet), "Classes"); 833 } 834 835 public void assertVariables(MemberInfo...expected) { 836 assertMembers(getState().variables(), Stream.of(expected).collect(Collectors.toSet())); 837 } 838 839 public void assertMethods(MemberInfo...expected) { 840 assertMembers(getState().methods(), Stream.of(expected).collect(Collectors.toSet())); 841 for (MethodSnippet methodKey : getState().methods()) { 842 MemberInfo expectedInfo = null; 843 for (MemberInfo info : expected) { 844 if (info.name.equals(methodKey.name()) && info.type.equals(methodKey.signature())) { 845 expectedInfo = getMemberInfo(methodKey); 846 } 847 } 848 assertNotNull(expectedInfo, "Not found method: " + methodKey.name()); 849 int lastIndexOf = expectedInfo.type.lastIndexOf(')'); 850 assertEquals(methodKey.parameterTypes(), expectedInfo.type.substring(1, lastIndexOf), "Parameter types"); 851 } 852 } 853 854 public void assertClasses(MemberInfo...expected) { 855 assertMembers(getState().types(), Stream.of(expected).collect(Collectors.toSet())); 856 } 857 858 public void assertCompletion(String code, String... expected) { 859 assertCompletion(code, null, expected); 860 } 861 862 public void assertCompletion(String code, Boolean isSmart, String... expected) { 863 List<String> completions = computeCompletions(code, isSmart); 864 assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString()); 865 } 866 867 public void assertCompletionIncludesExcludes(String code, Set<String> expected, Set<String> notExpected) { 868 assertCompletionIncludesExcludes(code, null, expected, notExpected); 869 } 870 871 public void assertCompletionIncludesExcludes(String code, Boolean isSmart, Set<String> expected, Set<String> notExpected) { 872 List<String> completions = computeCompletions(code, isSmart); 873 assertTrue(completions.containsAll(expected), String.valueOf(completions)); 874 assertTrue(Collections.disjoint(completions, notExpected), String.valueOf(completions)); 875 } 876 877 private List<String> computeCompletions(String code, Boolean isSmart) { 878 waitIndexingFinished(); 879 880 int cursor = code.indexOf('|'); 881 code = code.replace("|", ""); 882 assertTrue(cursor > -1, "'|' expected, but not found in: " + code); 883 List<Suggestion> completions = 884 getAnalysis().completionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now 885 return completions.stream() 886 .filter(s -> isSmart == null || isSmart == s.matchesType()) 887 .map(s -> s.continuation()) 888 .distinct() 889 .collect(Collectors.toList()); 890 } 891 892 public void assertInferredType(String code, String expectedType) { 893 String inferredType = getAnalysis().analyzeType(code, code.length()); 894 895 assertEquals(inferredType, expectedType, "Input: " + code + ", " + inferredType); 896 } 897 898 public void assertInferredFQNs(String code, String... fqns) { 899 assertInferredFQNs(code, code.length(), false, fqns); 900 } 901 902 public void assertInferredFQNs(String code, int simpleNameLen, boolean resolvable, String... fqns) { 903 waitIndexingFinished(); 904 905 QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length()); 906 907 assertEquals(candidates.getNames(), Arrays.asList(fqns), "Input: " + code + ", candidates=" + candidates.getNames()); 908 assertEquals(candidates.getSimpleNameLength(), simpleNameLen, "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength()); 909 assertEquals(candidates.isResolvable(), resolvable, "Input: " + code + ", resolvable=" + candidates.isResolvable()); 910 } 911 912 protected void waitIndexingFinished() { 913 try { 914 Method waitBackgroundTaskFinished = getAnalysis().getClass().getDeclaredMethod("waitBackgroundTaskFinished"); 915 916 waitBackgroundTaskFinished.setAccessible(true); 917 waitBackgroundTaskFinished.invoke(getAnalysis()); 918 } catch (Exception ex) { 919 throw new AssertionError("Cannot wait for indexing end.", ex); 920 } 921 } 922 923 public void assertDocumentation(String code, String... expected) { 924 int cursor = code.indexOf('|'); 925 code = code.replace("|", ""); 926 assertTrue(cursor > -1, "'|' expected, but not found in: " + code); 927 String documentation = getAnalysis().documentation(code, cursor); 928 Set<String> docSet = Stream.of(documentation.split("\r?\n")).collect(Collectors.toSet()); 929 Set<String> expectedSet = Stream.of(expected).collect(Collectors.toSet()); 930 assertEquals(docSet, expectedSet, "Input: " + code); 931 } 932 933 public enum ClassType { 934 CLASS("CLASS_SUBKIND") { 935 @Override 936 public String toString() { 937 return "class"; 938 } 939 }, 940 ENUM("ENUM_SUBKIND") { 941 @Override 942 public String toString() { 943 return "enum"; 944 } 945 }, 946 INTERFACE("INTERFACE_SUBKIND") { 947 @Override 948 public String toString() { 949 return "interface"; 950 } 951 }, 952 ANNOTATION("ANNOTATION_TYPE_SUBKIND") { 953 @Override 954 public String toString() { 955 return "@interface"; 956 } 957 }; 958 959 private final String classType; 960 961 ClassType(String classType) { 962 this.classType = classType; 963 } 964 965 public String getClassType() { 966 return classType; 967 } 968 969 @Override 970 public abstract String toString(); 971 } 972 973 public static MemberInfo variable(String type, String name) { 974 return new MemberInfo(type, name); 975 } 976 977 public static MemberInfo method(String signature, String name) { 978 return new MemberInfo(signature, name); 979 } 980 981 public static MemberInfo clazz(ClassType classType, String className) { 982 return new MemberInfo(classType.getClassType(), className); 983 } 984 985 public static class MemberInfo { 986 public final String type; 987 public final String name; 988 989 public MemberInfo(String type, String name) { 990 this.type = type; 991 this.name = name; 992 } 993 994 @Override 995 public int hashCode() { 996 return type.hashCode() + 3 * name.hashCode(); 997 } 998 999 @Override 1000 public boolean equals(Object o) { 1001 if (o instanceof MemberInfo) { 1002 MemberInfo other = (MemberInfo) o; 1003 return type.equals(other.type) && name.equals(other.name); 1004 } 1005 return false; 1006 } 1007 1008 @Override 1009 public String toString() { 1010 return String.format("%s %s", type, name); 1011 } 1012 } 1013 1014 public MemberInfo getMemberInfo(Snippet key) { 1015 SubKind subkind = key.subKind(); 1016 switch (subkind) { 1017 case CLASS_SUBKIND: 1018 case INTERFACE_SUBKIND: 1019 case ENUM_SUBKIND: 1020 case ANNOTATION_TYPE_SUBKIND: 1021 return new MemberInfo(subkind.name(), ((DeclarationSnippet) key).name()); 1022 case METHOD_SUBKIND: 1023 MethodSnippet method = (MethodSnippet) key; 1024 return new MemberInfo(method.signature(), method.name()); 1025 case VAR_DECLARATION_SUBKIND: 1026 case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: 1027 case TEMP_VAR_EXPRESSION_SUBKIND: 1028 VarSnippet var = (VarSnippet) key; 1029 return new MemberInfo(var.typeName(), var.name()); 1030 default: 1031 throw new AssertionError("Unknown snippet : " + key.kind() + " in expression " + key.toString()); 1032 } 1033 } 1034 1035 public String diagnosticsToString(List<Diag> diagnostics) { 1036 StringWriter writer = new StringWriter(); 1037 for (Diag diag : diagnostics) { 1038 writer.write("Error --\n"); 1039 for (String line : diag.getMessage(null).split("\\r?\\n")) { 1040 writer.write(String.format("%s\n", line)); 1041 } 1042 } 1043 return writer.toString().replace("\n", System.lineSeparator()); 1044 } 1045 1046 public boolean hasFatalError(List<Diag> diagnostics) { 1047 for (Diag diag : diagnostics) { 1048 if (diag.isError()) { 1049 return true; 1050 } 1051 } 1052 return false; 1053 } 1054 1055 public static EventChain chain(STEInfo mainInfo, STEInfo... updates) { 1056 return chain(mainInfo, IGNORE_VALUE, null, updates); 1057 } 1058 1059 public static EventChain chain(STEInfo mainInfo, String value, Class<? extends Throwable> exceptionClass, STEInfo... updates) { 1060 return new EventChain(mainInfo, value, exceptionClass, updates); 1061 } 1062 1063 public static STEInfo ste(Snippet key, Status previousStatus, Status status, 1064 Boolean isSignatureChange, Snippet causeKey) { 1065 return new STEInfo(key, previousStatus, status, isSignatureChange, causeKey); 1066 } 1067 1068 public static STEInfo added(Status status) { 1069 return new STEInfo(MAIN_SNIPPET, NONEXISTENT, status, status.isDefined(), null); 1070 } 1071 1072 public static class EventChain { 1073 public final STEInfo mainInfo; 1074 public final STEInfo[] updates; 1075 public final String value; 1076 public final Class<? extends Throwable> exceptionClass; 1077 1078 public EventChain(STEInfo mainInfo, String value, Class<? extends Throwable> exceptionClass, STEInfo... updates) { 1079 this.mainInfo = mainInfo; 1080 this.updates = updates; 1081 this.value = value; 1082 this.exceptionClass = exceptionClass; 1083 } 1084 } 1085 1086 public static class STEInfo { 1087 1088 STEInfo(Snippet snippet, Status previousStatus, Status status, 1089 Boolean isSignatureChange, Snippet causeSnippet) { 1090 this.snippet = snippet; 1091 this.previousStatus = previousStatus; 1092 this.status = status; 1093 this.checkIsSignatureChange = isSignatureChange != null; 1094 this.isSignatureChange = checkIsSignatureChange ? isSignatureChange : false; 1095 this.causeSnippet = causeSnippet; 1096 assertTrue(snippet != null, "Bad test set-up. The match snippet must not be null"); 1097 } 1098 1099 final Snippet snippet; 1100 final Status previousStatus; 1101 final Status status; 1102 final boolean isSignatureChange; 1103 final Snippet causeSnippet; 1104 1105 final boolean checkIsSignatureChange; 1106 public Snippet snippet() { 1107 return snippet; 1108 } 1109 public Status previousStatus() { 1110 return previousStatus; 1111 } 1112 public Status status() { 1113 return status; 1114 } 1115 public boolean isSignatureChange() { 1116 if (!checkIsSignatureChange) { 1117 throw new IllegalStateException("isSignatureChange value is undefined"); 1118 } 1119 return isSignatureChange; 1120 } 1121 public Snippet causeSnippet() { 1122 return causeSnippet; 1123 } 1124 public String value() { 1125 return null; 1126 } 1127 public Exception exception() { 1128 return null; 1129 } 1130 1131 public void assertMatch(SnippetEvent ste, Snippet mainSnippet) { 1132 assertKeyMatch(ste, ste.snippet(), snippet(), mainSnippet); 1133 assertStatusMatch(ste, ste.previousStatus(), previousStatus()); 1134 assertStatusMatch(ste, ste.status(), status()); 1135 if (checkIsSignatureChange) { 1136 assertEquals(ste.isSignatureChange(), isSignatureChange(), 1137 "Expected " + 1138 (isSignatureChange()? "" : "no ") + 1139 "signature-change, got: " + 1140 (ste.isSignatureChange()? "" : "no ") + 1141 "signature-change" + 1142 "\n expected-event: " + this + "\n got-event: " + toString(ste)); 1143 } 1144 assertKeyMatch(ste, ste.causeSnippet(), causeSnippet(), mainSnippet); 1145 } 1146 1147 private void assertKeyMatch(SnippetEvent ste, Snippet sn, Snippet expected, Snippet mainSnippet) { 1148 Snippet testKey = expected; 1149 if (testKey != null) { 1150 if (expected == MAIN_SNIPPET) { 1151 assertNotNull(mainSnippet, "MAIN_SNIPPET used, test must pass value to assertMatch"); 1152 testKey = mainSnippet; 1153 } 1154 if (ste.causeSnippet() == null && ste.status() != DROPPED && expected != MAIN_SNIPPET) { 1155 // Source change, always new snippet -- only match id() 1156 assertTrue(sn != testKey, 1157 "Main-event: Expected new snippet to be != : " + testKey 1158 + "\n got-event: " + toString(ste)); 1159 assertEquals(sn.id(), testKey.id(), "Expected IDs to match: " + testKey + ", got: " + sn 1160 + "\n expected-event: " + this + "\n got-event: " + toString(ste)); 1161 } else { 1162 assertEquals(sn, testKey, "Expected key to be: " + testKey + ", got: " + sn 1163 + "\n expected-event: " + this + "\n got-event: " + toString(ste)); 1164 } 1165 } 1166 } 1167 1168 private void assertStatusMatch(SnippetEvent ste, Status status, Status expected) { 1169 if (expected != null) { 1170 assertEquals(status, expected, "Expected status to be: " + expected + ", got: " + status + 1171 "\n expected-event: " + this + "\n got-event: " + toString(ste)); 1172 } 1173 } 1174 1175 @Override 1176 public String toString() { 1177 return "STEInfo key: " + 1178 (snippet()==MAIN_SNIPPET? "MAIN_SNIPPET" : (snippet()==null? "ignore" : snippet().id())) + 1179 " before: " + previousStatus() + 1180 " status: " + status() + " sig: " + isSignatureChange() + 1181 " cause: " + (causeSnippet()==null? "null" : causeSnippet().id()); 1182 } 1183 1184 private String toString(SnippetEvent ste) { 1185 return "key: " + (ste.snippet()==MAIN_SNIPPET? "MAIN_SNIPPET" : ste.snippet().id()) + " before: " + ste.previousStatus() 1186 + " status: " + ste.status() + " sig: " + ste.isSignatureChange() 1187 + " cause: " + ste.causeSnippet(); 1188 } 1189 } 1190 }