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