Skip to content

Commit 1cfe107

Browse files
lauraharkercopybara-github
authored andcommitted
Extract some logic in CompilerTestCase::testInternal into helper methods
(This was specifically motivated by trying to figure out why there were so many .isEquivalentTo calls - turns out there are some that are only needed for change reporting verification, so this CL refactors those calls to only run if we are actually verifying change reporting). PiperOrigin-RevId: 845312588
1 parent f6acced commit 1cfe107

File tree

1 file changed

+152
-118
lines changed

1 file changed

+152
-118
lines changed

test/com/google/javascript/jscomp/CompilerTestCase.java

Lines changed: 152 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,6 @@ private void testInternal(
11501150

11511151
int numRepetitions = getNumRepetitions();
11521152
ErrorManager[] errorManagers = new ErrorManager[numRepetitions];
1153-
int aggregateWarningCount = 0;
11541153
List<JSError> aggregateWarnings = new ArrayList<>();
11551154
boolean hasCodeChanged = false;
11561155

@@ -1339,7 +1338,6 @@ private void testInternal(
13391338
}
13401339

13411340
hasCodeChanged = hasCodeChanged || recentChange.hasCodeChanged();
1342-
aggregateWarningCount += errorManagers[i].getWarningCount();
13431341
aggregateWarnings.addAll(compiler.getWarnings());
13441342

13451343
if (normalizeEnabled) {
@@ -1353,45 +1351,10 @@ private void testInternal(
13531351
if (expectedErrors.isEmpty()) {
13541352
assertThat(compiler.getErrors()).isEmpty();
13551353

1356-
// Verify the symbol table.
1357-
ErrorManager symbolTableErrorManager = new BlackHoleErrorManager();
1358-
compiler.setErrorManager(symbolTableErrorManager);
1359-
Node expectedRoot = null;
1360-
if (expected != null) {
1361-
expectedRoot = parseExpectedJs(expected);
1362-
}
1354+
validateWarnings(
1355+
compiler, expectedWarnings, errorManagers, aggregateWarnings, numRepetitions);
13631356

1364-
ImmutableList<JSError> stErrors = symbolTableErrorManager.getErrors();
1365-
if (expectedSymbolTableError != null) {
1366-
assertError(getOnlyElement(stErrors)).hasType(expectedSymbolTableError);
1367-
} else {
1368-
assertWithMessage("symbol table errors").that(stErrors).isEmpty();
1369-
}
1370-
LightweightMessageFormatter formatter = new LightweightMessageFormatter(compiler);
1371-
if (expectedWarnings.isEmpty()) {
1372-
assertWithMessage(
1373-
"aggregate warnings: %s",
1374-
aggregateWarnings.stream().map(formatter::formatWarning).collect(joining("\n")))
1375-
.that(aggregateWarnings)
1376-
.isEmpty();
1377-
} else {
1378-
assertWithMessage(
1379-
"There should be %s warnings, repeated %s time(s). Warnings: \n%s",
1380-
expectedWarnings.size(), numRepetitions, LINE_JOINER.join(aggregateWarnings))
1381-
.that(aggregateWarningCount)
1382-
.isEqualTo(numRepetitions * expectedWarnings.size());
1383-
for (int i = 0; i < numRepetitions; i++) {
1384-
assertWithMessage("compile warnings from repetition %s", (i + 1))
1385-
.that(errorManagers[i].getWarnings())
1386-
.comparingElementsUsing(DIAGNOSTIC_CORRESPONDENCE)
1387-
.containsExactlyElementsIn(expectedWarnings);
1388-
for (JSError warning : errorManagers[i].getWarnings()) {
1389-
validateSourceLocation(warning);
1390-
}
1391-
}
1392-
}
1393-
1394-
// If we ran normalize on the AST, we must also run normalize on th clone before checking for
1357+
// If we ran normalize on the AST, we must also run normalize on the clone before checking for
13951358
// changes.
13961359
if (normalizeEnabled) {
13971360
boolean hasTypecheckingRun = compiler.hasTypeCheckingRun();
@@ -1402,92 +1365,21 @@ private void testInternal(
14021365
compiler.setTypeCheckingHasRun(hasTypecheckingRun);
14031366
}
14041367

1405-
boolean codeChange = !mainRootClone.isEquivalentWithSideEffectsTo(mainRoot);
1406-
boolean externsChange = !externsRootClone.isEquivalentWithSideEffectsTo(externsRoot);
1407-
1408-
// Generally, externs should not be changed by the compiler passes.
1409-
if (externsChange && !allowExternsChanges) {
1410-
assertNode(externsRoot)
1411-
.usingSerializer(createPrettyPrinter(compiler))
1412-
.isEqualTo(externsRootClone);
1413-
}
1414-
1415-
if (checkAstChangeMarking) {
1416-
if (!codeChange && !externsChange) {
1417-
assertWithMessage("compiler.reportCodeChange() was called even though nothing changed")
1418-
.that(hasCodeChanged)
1419-
.isFalse();
1420-
} else {
1421-
assertWithMessage(
1422-
"compiler.reportCodeChange() should have been called."
1423-
+ "\nOriginal: %s\nNew: %s",
1424-
mainRootClone.toStringTree(), mainRoot.toStringTree())
1425-
.that(hasCodeChanged)
1426-
.isTrue();
1427-
}
1368+
if (checkAstChangeMarking || !allowExternsChanges) {
1369+
validateCodeChangeReporting(
1370+
mainRoot, externsRoot, mainRootClone, externsRootClone, compiler, hasCodeChanged);
14281371
}
14291372

14301373
if (expected != null) {
1431-
if (!compareSyntheticCode) {
1432-
Node scriptRoot = mainRoot.getFirstChild();
1433-
for (Node child = scriptRoot.getFirstChild(); child != null; ) {
1434-
Node nextChild = child.getNext();
1435-
if (NodeUtil.isInSyntheticScript(child)) {
1436-
child.detach();
1437-
}
1438-
child = nextChild;
1439-
}
1440-
}
1374+
Node expectedRoot = parseExpectedJs(expected);
14411375
if (compareAsTree) {
1442-
if (compareJsDoc) {
1443-
assertNode(mainRoot)
1444-
.usingSerializer(createPrettyPrinter(compiler))
1445-
.withGenericNameReplacements(ImmutableMap.copyOf(genericNameMapping))
1446-
.isEqualIncludingJsDocTo(expectedRoot);
1447-
} else {
1448-
assertNode(mainRoot)
1449-
.usingSerializer(createPrettyPrinter(compiler))
1450-
.withGenericNameReplacements(ImmutableMap.copyOf(genericNameMapping))
1451-
.isEqualTo(expectedRoot);
1452-
}
1376+
compareExpectedToActualAsTree(mainRoot, expectedRoot, compiler, genericNameMapping);
14531377
} else {
1454-
String[] expectedSources = new String[expected.size()];
1455-
for (int i = 0; i < expected.size(); ++i) {
1456-
try {
1457-
expectedSources[i] = expected.get(i).getCode();
1458-
} catch (IOException e) {
1459-
throw new RuntimeException("failed to get source code", e);
1460-
}
1461-
}
1462-
assertThat(compiler.toSource(mainRoot).replaceAll(" +\n", "\n"))
1463-
.isEqualTo(Joiner.on("").join(expectedSources));
1378+
compareExpectedToActualAsStrings(mainRoot, compiler, expected);
14641379
}
14651380
}
14661381

1467-
// Verify normalization is not invalidated.
1468-
Node normalizeCheckRootClone = root.cloneTree();
1469-
Node normalizeCheckExternsRootClone = normalizeCheckRootClone.getFirstChild();
1470-
Node normalizeCheckMainRootClone = normalizeCheckRootClone.getLastChild();
1471-
1472-
assertNode(normalizeCheckMainRootClone)
1473-
.usingSerializer(createPrettyPrinter(compiler))
1474-
.isEqualTo(mainRoot);
1475-
1476-
// TODO(johnlenz): enable this for most test cases.
1477-
// Currently, this invalidates test for while-loops, for-loop
1478-
// initializers, and other naming. However, a set of code
1479-
// (Closure primitive rewrites, etc) runs before the Normalize pass,
1480-
// so this can't be force on everywhere.
1481-
if (normalizeEnabled) {
1482-
Normalize.builder(compiler)
1483-
.assertOnChange(true)
1484-
.build()
1485-
.process(normalizeCheckExternsRootClone, normalizeCheckMainRootClone);
1486-
1487-
assertNode(normalizeCheckMainRootClone)
1488-
.usingSerializer(createPrettyPrinter(compiler))
1489-
.isEqualTo(mainRoot);
1490-
}
1382+
validateNormalizationInvariants(root, compiler);
14911383
} else {
14921384
assertWithMessage("compile errors")
14931385
.that(compiler.getErrors())
@@ -1560,6 +1452,148 @@ private void transpileToEs5(AbstractCompiler compiler, Node externsRoot, Node co
15601452
}
15611453
}
15621454

1455+
private void validateWarnings(
1456+
Compiler compiler,
1457+
List<Diagnostic> expectedWarnings,
1458+
ErrorManager[] errorManagers,
1459+
List<JSError> aggregateWarnings,
1460+
int numRepetitions) {
1461+
// Verify the symbol table.
1462+
// TODO: lharker - why is this necessary?
1463+
ErrorManager symbolTableErrorManager = new BlackHoleErrorManager();
1464+
compiler.setErrorManager(symbolTableErrorManager);
1465+
1466+
ImmutableList<JSError> stErrors = symbolTableErrorManager.getErrors();
1467+
if (expectedSymbolTableError != null) {
1468+
assertError(getOnlyElement(stErrors)).hasType(expectedSymbolTableError);
1469+
} else {
1470+
assertWithMessage("symbol table errors").that(stErrors).isEmpty();
1471+
}
1472+
1473+
LightweightMessageFormatter formatter = new LightweightMessageFormatter(compiler);
1474+
if (expectedWarnings.isEmpty()) {
1475+
assertWithMessage(
1476+
"aggregate warnings: %s",
1477+
aggregateWarnings.stream().map(formatter::formatWarning).collect(joining("\n")))
1478+
.that(aggregateWarnings)
1479+
.isEmpty();
1480+
} else {
1481+
assertWithMessage(
1482+
"There should be %s warnings, repeated %s time(s). Warnings: \n%s",
1483+
expectedWarnings.size(), numRepetitions, LINE_JOINER.join(aggregateWarnings))
1484+
.that(aggregateWarnings.size())
1485+
.isEqualTo(numRepetitions * expectedWarnings.size());
1486+
for (int i = 0; i < numRepetitions; i++) {
1487+
assertWithMessage("compile warnings from repetition %s", (i + 1))
1488+
.that(errorManagers[i].getWarnings())
1489+
.comparingElementsUsing(DIAGNOSTIC_CORRESPONDENCE)
1490+
.containsExactlyElementsIn(expectedWarnings);
1491+
for (JSError warning : errorManagers[i].getWarnings()) {
1492+
validateSourceLocation(warning);
1493+
}
1494+
}
1495+
}
1496+
}
1497+
1498+
private void validateCodeChangeReporting(
1499+
Node mainRoot,
1500+
Node externsRoot,
1501+
Node mainRootClone,
1502+
Node externsRootClone,
1503+
Compiler compiler,
1504+
boolean wasCodeChangeReported) {
1505+
boolean codeChange = !mainRootClone.isEquivalentWithSideEffectsTo(mainRoot);
1506+
boolean externsChange = !externsRootClone.isEquivalentWithSideEffectsTo(externsRoot);
1507+
1508+
// Generally, externs should not be changed by the compiler passes.
1509+
if (externsChange && !allowExternsChanges) {
1510+
assertNode(externsRoot)
1511+
.usingSerializer(createPrettyPrinter(compiler))
1512+
.isEqualTo(externsRootClone);
1513+
}
1514+
if (checkAstChangeMarking) {
1515+
if (!codeChange && !externsChange) {
1516+
assertWithMessage("compiler.reportCodeChange() was called even though nothing changed")
1517+
.that(wasCodeChangeReported)
1518+
.isFalse();
1519+
} else {
1520+
assertWithMessage(
1521+
"compiler.reportCodeChange() should have been called." + "\nOriginal: %s\nNew: %s",
1522+
mainRootClone.toStringTree(), mainRoot.toStringTree())
1523+
.that(wasCodeChangeReported)
1524+
.isTrue();
1525+
}
1526+
}
1527+
}
1528+
1529+
private void compareExpectedToActualAsTree(
1530+
Node mainRoot, Node expectedRoot, Compiler compiler, Map<String, String> genericNameMapping) {
1531+
if (!compareSyntheticCode) {
1532+
Node scriptRoot = mainRoot.getFirstChild();
1533+
for (Node child = scriptRoot.getFirstChild(); child != null; ) {
1534+
Node nextChild = child.getNext();
1535+
if (NodeUtil.isInSyntheticScript(child)) {
1536+
child.detach();
1537+
}
1538+
child = nextChild;
1539+
}
1540+
}
1541+
if (compareJsDoc) {
1542+
assertNode(mainRoot)
1543+
.usingSerializer(createPrettyPrinter(compiler))
1544+
.withGenericNameReplacements(ImmutableMap.copyOf(genericNameMapping))
1545+
.isEqualIncludingJsDocTo(expectedRoot);
1546+
} else {
1547+
assertNode(mainRoot)
1548+
.usingSerializer(createPrettyPrinter(compiler))
1549+
.withGenericNameReplacements(ImmutableMap.copyOf(genericNameMapping))
1550+
.isEqualTo(expectedRoot);
1551+
}
1552+
}
1553+
1554+
private void compareExpectedToActualAsStrings(
1555+
Node mainRoot, Compiler compiler, List<SourceFile> expected) {
1556+
String[] expectedSources = new String[expected.size()];
1557+
for (int i = 0; i < expected.size(); ++i) {
1558+
try {
1559+
expectedSources[i] = expected.get(i).getCode();
1560+
} catch (IOException e) {
1561+
throw new RuntimeException("failed to get source code", e);
1562+
}
1563+
}
1564+
assertThat(compiler.toSource(mainRoot).replaceAll(" +\n", "\n"))
1565+
.isEqualTo(Joiner.on("").join(expectedSources));
1566+
}
1567+
1568+
private void validateNormalizationInvariants(Node root, Compiler compiler) {
1569+
Node mainRoot = root.getLastChild();
1570+
1571+
// Verify normalization is not invalidated.
1572+
Node normalizeCheckRootClone = root.cloneTree();
1573+
Node normalizeCheckExternsRootClone = normalizeCheckRootClone.getFirstChild();
1574+
Node normalizeCheckMainRootClone = normalizeCheckRootClone.getLastChild();
1575+
1576+
assertNode(normalizeCheckMainRootClone)
1577+
.usingSerializer(createPrettyPrinter(compiler))
1578+
.isEqualTo(mainRoot);
1579+
1580+
// TODO(johnlenz): enable this for most test cases.
1581+
// Currently, this invalidates test for while-loops, for-loop
1582+
// initializers, and other naming. However, a set of code
1583+
// (Closure primitive rewrites, etc) runs before the Normalize pass,
1584+
// so this can't be force on everywhere.
1585+
if (normalizeEnabled) {
1586+
Normalize.builder(compiler)
1587+
.assertOnChange(true)
1588+
.build()
1589+
.process(normalizeCheckExternsRootClone, normalizeCheckMainRootClone);
1590+
1591+
assertNode(normalizeCheckMainRootClone)
1592+
.usingSerializer(createPrettyPrinter(compiler))
1593+
.isEqualTo(mainRoot);
1594+
}
1595+
}
1596+
15631597
private void validateSourceLocation(JSError jserror) {
15641598
// Make sure that source information is always provided.
15651599
if (!allowSourcelessWarnings) {

0 commit comments

Comments
 (0)