/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SourceMetricFinder_Test.java * Creation date: (Jul 7, 2005) * By: Jawright */ package org.openquark.cal.compiler; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import junit.extensions.TestSetup; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.openquark.cal.CALPlatformTestModuleNames; import org.openquark.cal.compiler.SourceMetricFinder.LintWarning; import org.openquark.cal.filter.AcceptAllQualifiedNamesFilter; import org.openquark.cal.filter.RegExpBasedUnqualifiedNameFilter; import org.openquark.cal.module.Cal.Collections.CAL_Array; import org.openquark.cal.module.Cal.Core.CAL_Prelude; import org.openquark.cal.module.Cal.Core.CAL_String; import org.openquark.cal.module.Cal.Utilities.CAL_StringNoCase; import org.openquark.cal.runtime.MachineType; import org.openquark.cal.services.BasicCALServices; import org.openquark.cal.services.CALServicesTestUtilities; import org.openquark.cal.services.Status; import org.openquark.util.Pair; /** * A set of JUnit tests for the SourceMetricFinder class. * Creation date: (Jul 7, 2005) * @author Jawright */ public class SourceMetricFinder_Test extends TestCase { /** * A copy of CAL services for use in the test cases. */ private static BasicCALServices leccCALServices; /** A cached reference to the workspace's metrics manager */ private static SourceMetrics workspaceSourceMetrics; /** A cached copy of the SourceModel for the support module */ private static SourceModel.ModuleDefn moduleDefn; /** A cached copy of the ModuleTypeInfo for the support module */ private static ModuleTypeInfo moduleTypeInfo; /** * @return a test suite containing all the test cases for testing CAL source * generation. */ public static Test suite() { TestSuite suite = new TestSuite(SourceMetricFinder_Test.class); return new TestSetup(suite) { protected void setUp() { oneTimeSetUp(); } protected void tearDown() { oneTimeTearDown(); } }; } /** * Performs the setup for the test suite. */ private static void oneTimeSetUp() { leccCALServices = CALServicesTestUtilities.getCommonCALServices(MachineType.LECC, "cal.platform.test.cws"); workspaceSourceMetrics = leccCALServices.getCALWorkspace().getSourceMetrics(); String moduleSource = readModuleSource(leccCALServices.getCALWorkspace().getSourceDefinition(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support)); moduleDefn = SourceModelUtilities.TextParsing.parseModuleDefnIntoSourceModel(moduleSource); moduleTypeInfo = leccCALServices.getWorkspaceManager().getModuleTypeInfo(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support); } /** * Performs the tear down for the test suite. */ private static void oneTimeTearDown() { leccCALServices = null; workspaceSourceMetrics = null; moduleDefn = null; moduleTypeInfo = null; } /** * Constructor for SourceMetricFinder_Test. * * @param name * the name of the test */ public SourceMetricFinder_Test(String name) { super(name); } /** * Tests that the reference frequency metrics behave the way that we expect in the basic cases. */ public void testReferenceFrequencyMetric() { assertEquals(0, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf0"))); assertEquals(1, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf1"))); assertEquals(2, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf2"))); assertEquals(3, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf3"))); assertEquals(2, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf4"))); } /** * Test that we correctly handle calls embedded in operator calls */ public void testReferenceFrequencyOperatorHandling() { assertEquals(3, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf5"))); } /** Test that we correctly handle scoping issues from lambda expressions and local functions */ public void testReferenceFrequencyLambdaAndLocalFunctionHandling() { assertEquals(4, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf6"))); } /** Test that functions called using the backquoted-operator syntax are counted */ public void testReferenceFrequencyBackquoteHandling() { assertEquals(1, workspaceSourceMetrics.getGemReferenceFrequency(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "leaf7"))); } /** Test that regular expression filtering is working */ public void testReferenceFrequencyRegexpFiltering() { Map<Pair<QualifiedName, QualifiedName>, Integer> unfilteredMap = SourceMetricFinder.computeReferenceFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); Map<Pair<QualifiedName, QualifiedName>, Integer> filteredMap = SourceMetricFinder.computeReferenceFrequencies(moduleDefn, moduleTypeInfo, new RegExpBasedUnqualifiedNameFilter(".*Examples", true), false); int unfilteredFrequency = 0; int filteredFrequency = 0; // Extract reference frequency for leaf8 for (final Pair<QualifiedName, QualifiedName> key : unfilteredMap.keySet()) { String dependeeName = key.fst().getUnqualifiedName(); if(dependeeName.equals("leaf8")) { Integer frequency = unfilteredMap.get(key); unfilteredFrequency += frequency.intValue(); } } for (final Pair<QualifiedName, QualifiedName> key : filteredMap.keySet()) { String dependeeName = key.fst().getUnqualifiedName(); if(dependeeName.equals("leaf8")) { Integer frequency = unfilteredMap.get(key); filteredFrequency += frequency.intValue(); } } assertEquals(2, unfilteredFrequency); assertEquals(1, filteredFrequency); } /** * Check that the compositional frequency metric behaves basically as we expect. */ public void testCompositionalFrequencyMetric() { Map<Pair<QualifiedName, QualifiedName>, Integer> compositionalFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); assertEquals(1, getCompositionalFrequency(compositionalFrequencies, "callerC1", "mangleValue")); assertEquals(2, getCompositionalFrequency(compositionalFrequencies, "mangleValue", "callerC1")); assertEquals(3, getCompositionalFrequency(compositionalFrequencies, "stompValue", "callerC1")); } /** Check that we handle Prelude.apply in both its function and operator ($) forms */ public void testCompositionFrequencyApplyHandling() { Map<Pair<QualifiedName, QualifiedName>, Integer> compositionalFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); assertEquals(1, getCompositionalFrequency(compositionalFrequencies, "mangleValue", "callerC2")); assertEquals(1, getCompositionalFrequency(compositionalFrequencies, "callerC2", "mangleValue")); assertEquals(2, getCompositionalFrequency(compositionalFrequencies, "callerC2a", "mangleValue")); } /** Check that we handle Prelude.compose in both its function and operator (#) forms */ public void testCompositionFrequencyComposeHandling() { Map<Pair<QualifiedName, QualifiedName>, Integer> compositionalFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); assertEquals(2, getCompositionalFrequency(compositionalFrequencies, "mangleValue", "callerC3")); assertEquals(2, getCompositionalFrequency(compositionalFrequencies, "callerC3", "mangleValue")); assertEquals(1, getCompositionalFrequency(compositionalFrequencies, "callerC3", "stompValue")); } /** Test that we deal properly with lambdas */ public void testCompositionFrequencyLambdaHandling() { Map<Pair<QualifiedName, QualifiedName>, Integer> compositionalFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); assertEquals(3, getCompositionalFrequency(compositionalFrequencies, "stompValue", "callerC4")); assertEquals(1, getCompositionalFrequency(compositionalFrequencies, "callerC4", "mangleValue")); assertEquals(0, getCompositionalFrequency(compositionalFrequencies, "mangleValue", "callerC4")); } /** Test regexp-filtering in compositional-frequency computation */ public void testCompositionalFrequencyRegexpFiltering() { Map<Pair<QualifiedName, QualifiedName>, Integer> unfilteredFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false); Map<Pair<QualifiedName, QualifiedName>, Integer> filteredFrequencies = SourceMetricFinder.computeCompositionalFrequencies(moduleDefn, moduleTypeInfo, new RegExpBasedUnqualifiedNameFilter("(.*test.*)|(.*Examples.*)", true), false); assertEquals(1, getCompositionalFrequency(filteredFrequencies, "callerC5", "mangleValue")); assertEquals(3, getCompositionalFrequency(unfilteredFrequencies, "callerC5", "mangleValue")); } /** Test redundant-lambda detection */ public void testLintWalkerRedundantLambdas() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, false, true, false, false, false); assertTrue(functionFlagged("l1", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertTrue(functionFlagged("l2", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertFalse(functionFlagged("l3", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertTrue(functionFlagged("l4", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertTrue(functionFlagged("l5", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertTrue(functionFlagged("l6", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); assertFalse(functionFlagged("l7", LintWarning.WarningType.REDUNDANT_LAMBDA, warningList)); } /** Test unplinged-primitive-arg detection */ public void testLintWalkerUnplingedPrimitveArgs() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, true, false, false, false, false); assertTrue(functionFlagged("fullyUnplingedPrimitives", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives1", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives2", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives3", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives4", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives5", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertTrue(functionFlagged("partiallyUnplingedPrimitives6", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertFalse(functionFlagged("fullyUnplingedConstrained", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); assertFalse(functionFlagged("fullyUnplingedAlgebraic", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, warningList)); } /** Test unreferenced-private-function detection */ public void testLintWalkerUnusedPrivates() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, false, false, true, false, false); assertFalse(functionFlagged("unreferencedPublicFunction", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertFalse(functionFlagged("referenced1", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertFalse(functionFlagged("referenced2", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertFalse(functionFlagged("referenced3", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertFalse(functionFlagged("referenced4", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertTrue(functionFlagged("unreferencedPrivate1", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); assertTrue(functionFlagged("unreferencedPrivate2", LintWarning.WarningType.UNUSED_PRIVATE_FUNCTION, warningList)); } /** Test mismatched-plings-on-alias-functions detection */ public void testLintWalkerMismatchedAliasPlings() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, false, false, false, true, false); assertFalse(functionFlagged("alias1", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias2", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias3", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias4", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias5", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias6", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias7", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias8", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias9", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias10", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("alias11", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias1", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias2", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias3", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias4", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias5", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias6", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertTrue(functionFlagged("badAlias7", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("partialAlias1", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("partialAlias2", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("partialAlias3", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("partialAlias4", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("partialAlias5", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias1", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias2", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias3", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias4", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias5", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); assertFalse(functionFlagged("notAlias6", LintWarning.WarningType.MISMATCHED_ALIAS_PLINGS, warningList)); } /** Test the detection of unreferenced let variables */ public void testUnreferencedLetVariableDetection() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, false, false, false, false, true); assertTrue(functionFlagged("unusedLetVars1", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars2", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars3", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars4", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars5", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars6", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars7", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars8", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars9", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars10", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars11", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertTrue(functionFlagged("unusedLetVars12", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertFalse(functionFlagged("usesLetVar1", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertFalse(functionFlagged("usesLetVar2", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertFalse(functionFlagged("usesLetVar3", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertFalse(functionFlagged("usesLetVar4", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); assertFalse(functionFlagged("usesLetVar5", LintWarning.WarningType.UNREFERENCED_LET_VARIABLE, warningList)); } /** Test that SourcePositions are correctly recorded for all warning types */ public void testSourcePositions() { List<LintWarning> warningList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, true, true, false, false, false); LintWarning[] veryLintyWarnings = new LintWarning[3]; int i = 0; for(Iterator<LintWarning> it = warningList.iterator(); it.hasNext() && i < 3;) { LintWarning warning = it.next(); if(warning.getFunctionName().getUnqualifiedName().equals("veryLintyFunction")) { veryLintyWarnings[i] = warning; i++; } } assertEquals(3, i); assertTrue(veryLintyWarnings[0].getSourcePosition() != null); assertTrue(veryLintyWarnings[1].getSourcePosition() != null); assertTrue(veryLintyWarnings[2].getSourcePosition() != null); // The two unplinged-primitive warnings should point at the same line assertEquals(veryLintyWarnings[0].getSourcePosition().getLine(), veryLintyWarnings[1].getSourcePosition().getLine()); // The second argument is 14 characters from the first assertEquals(veryLintyWarnings[0].getSourcePosition().getColumn() + 14, veryLintyWarnings[1].getSourcePosition().getColumn()); // The redundant-lambda warning should occur on the next line from the parameter warnings assertEquals(veryLintyWarnings[0].getSourcePosition().getLine() + 1, veryLintyWarnings[2].getSourcePosition().getLine()); // The lambda begins at the same column as the first parameter assertEquals(veryLintyWarnings[0].getSourcePosition().getColumn(), veryLintyWarnings[2].getSourcePosition().getColumn()); } /** Test that warning filtering is working */ public void testWarningTypeFilter() { List<LintWarning> lambdasOnlyList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, false, true, false, false, false); List<LintWarning> plingsOnlyList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, true, false, false, false, false); assertTrue(lambdasOnlyList.size() > 0); for (final LintWarning warning : lambdasOnlyList) { assertTrue(warning.getWarningType() == LintWarning.WarningType.REDUNDANT_LAMBDA); } assertTrue(plingsOnlyList.size() > 0); for (final LintWarning warning : plingsOnlyList) { assertTrue(warning.getWarningType() == LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG); } } /** Test that function regular expression filtering is working */ public void testLintWalkerRegexpFiltering() { List<LintWarning> unfilteredWarningsList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new AcceptAllQualifiedNamesFilter(), false, true, false, false, false, false); List<LintWarning> filteredWarningsList = SourceMetricFinder.computeLintWarnings(moduleDefn, moduleTypeInfo, new RegExpBasedUnqualifiedNameFilter("very.*", true), false, true, false, false, false, false); assertTrue(functionFlagged("veryLintyFunction", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, unfilteredWarningsList)); assertFalse(functionFlagged("veryLintyFunction", LintWarning.WarningType.UNPLINGED_PRIMITIVE_ARG, filteredWarningsList)); } /** Test the basic operation of search */ public void testSearchWalker() { QualifiedName sillyFunctionName = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "sillyFunction"); List<SearchResult.Precise> fcnDefnList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.DEFINITION, Collections.singletonList(sillyFunctionName)); // We will make various assertions about source positions relative to the position of sillyFunction's definition assertEquals(1, fcnDefnList.size()); SearchResult.Precise fcnDefnResult = fcnDefnList.get(0); assertEquals(1, fcnDefnResult.getSourcePosition().getColumn()); int baseLine = fcnDefnResult.getSourcePosition().getLine(); List<SearchResult.Precise> refList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Collections.singletonList(sillyFunctionName)); assertEquals(3, refList.size()); assertEquals(baseLine + 4, line(refList.get(0))); assertEquals(6, column(refList.get(0))); assertEquals(baseLine + 4, line(refList.get(1))); assertEquals(28, column(refList.get(1))); assertEquals(baseLine + 14, line(refList.get(2))); assertEquals(29, column(refList.get(2))); QualifiedName equalsName = CAL_Prelude.Functions.equals; List<SearchResult.Precise> equalsRefList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Collections.singletonList(equalsName)); assertEquals(2, equalsRefList.size()); assertEquals(baseLine + 18, line(equalsRefList.get(0))); assertEquals(16, column(equalsRefList.get(0))); assertEquals(baseLine + 19, line(equalsRefList.get(1))); assertEquals(19, column(equalsRefList.get(1))); QualifiedName sillyDataTypeName = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "SillyDataType"); List<SearchResult.Precise> sillyDataTypeDefnList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.DEFINITION, Collections.singletonList(sillyDataTypeName)); assertEquals(2, sillyDataTypeDefnList.size()); assertEquals(baseLine + 21, line(sillyDataTypeDefnList.get(0))); assertEquals(14, column(sillyDataTypeDefnList.get(0))); assertEquals(baseLine + 22, line(sillyDataTypeDefnList.get(1))); assertEquals(5, column(sillyDataTypeDefnList.get(1))); QualifiedName identifiableName = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "Identifiable"); List<SearchResult.Precise> identifiableDefnList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.DEFINITION, Collections.singletonList(identifiableName)); assertEquals(1, identifiableDefnList.size()); assertEquals(baseLine + 26, line(identifiableDefnList.get(0))); assertEquals(7, column(identifiableDefnList.get(0))); List<SearchResult.Precise> identifiableInstances = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.INSTANCES, Collections.singletonList(identifiableName)); List<SearchResult.Precise> sillyDataTypeClasses = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.CLASSES, Collections.singletonList(sillyDataTypeName)); assertEquals(1, identifiableInstances.size()); assertEquals(2, sillyDataTypeClasses.size()); assertEquals(baseLine + 24, line(sillyDataTypeClasses.get(0))); assertEquals(14, column(sillyDataTypeClasses.get(0))); // only instance of Identifiable is the second class to which SillyDataType belongs assertEquals(line(identifiableInstances.get(0)), line(sillyDataTypeClasses.get(1))); assertEquals(column(identifiableInstances.get(0)), 10); QualifiedName sillyDataconsName = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "Silly"); List<SearchResult.Precise> sillyDataconsDefnList = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.DEFINITION, Collections.singletonList(sillyDataconsName)); assertEquals(1, sillyDataconsDefnList.size()); assertEquals(baseLine + 23, line(sillyDataconsDefnList.get(0))); assertEquals(5, column(sillyDataconsDefnList.get(0))); List<SearchResult.Precise> sillyDataconsRefs = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Collections.singletonList(sillyDataconsName)); assertEquals(3, sillyDataconsRefs.size()); assertEquals(baseLine + 35, line(sillyDataconsRefs.get(0))); assertEquals(9, column(sillyDataconsRefs.get(0))); assertEquals(baseLine + 39, line(sillyDataconsRefs.get(1))); assertEquals(6, column(sillyDataconsRefs.get(1))); assertEquals(baseLine + 39, line(sillyDataconsRefs.get(2))); assertEquals(40, column(sillyDataconsRefs.get(2))); List<QualifiedName> toListNames = new ArrayList<QualifiedName>(2); toListNames.add(CAL_Array.Functions.toList); toListNames.add(CAL_String.Functions.toList); List<SearchResult.Precise> toListRefs = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, toListNames); assertEquals(2, toListRefs.size()); assertEquals(baseLine + 56, line(toListRefs.get(0))); assertEquals(15, column(toListRefs.get(0))); assertEquals(baseLine + 57, line(toListRefs.get(1))); assertEquals(16, column(toListRefs.get(1))); List<SearchResult.Precise> idReferences = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Collections.singletonList(CAL_Prelude.Functions.id)); assertEquals(1, idReferences.size()); assertEquals(baseLine + 31, line(idReferences.get(0))); assertEquals(24, column(idReferences.get(0))); // Test that we deal correctly with identical names in different namespaces // (eg, typeconses and dataconses with the same name). List<SearchResult.Precise> crossConsResults = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.DEFINITION, Collections.singletonList(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "ConsName1"))); assertTrue(crossConsResults.size() == 2); assertEquals(baseLine + 60, line(crossConsResults.get(0))); assertEquals(14, column(crossConsResults.get(0))); assertEquals(baseLine + 65, line(crossConsResults.get(1))); assertEquals(5, column(crossConsResults.get(1))); // Test special-notation type constructor support List<SearchResult.Precise> listAndFcnInstances = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.CLASSES, Arrays.asList(new QualifiedName[] {CAL_Prelude.TypeConstructors.Function, CAL_Prelude.TypeConstructors.List})); List<SearchResult.Precise> constantableInstances = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.INSTANCES, Collections.singletonList(QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, "Constantable"))); // The only List and Function instances in SourceMetricFinder_Test_Support are of Constantable, // which has no other instances. assertEquals(2, listAndFcnInstances.size()); assertEquals(2, constantableInstances.size()); for(int i = 0; i < listAndFcnInstances.size(); i++) { assertEquals(line(listAndFcnInstances.get(i)), line(constantableInstances.get(i))); // We don't check columns for equality, because in one case it will be point // to the type whereas in the other case it will point to the class. } // Test special-notation list data constructor support List<SearchResult.Precise> listReferences = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Arrays.asList(new QualifiedName[] {CAL_Prelude.DataConstructors.Cons, CAL_Prelude.DataConstructors.Nil})); assertEquals(7, listReferences.size()); // The first four references are part of the linter test and don't have // guaranteed positions, so we skip them assertEquals(baseLine + 71, line(listReferences.get(4))); assertEquals(5, column(listReferences.get(4))); assertEquals(baseLine + 72, line(listReferences.get(5))); assertEquals(7, column(listReferences.get(5))); assertEquals(baseLine + 77, line(listReferences.get(6))); assertEquals(9, column(listReferences.get(6))); // Test searching of using clauses List<SearchResult.Precise> fromStringOccurences = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.ALL, Collections.singletonList(CAL_StringNoCase.Functions.fromString)); assertEquals(1, fromStringOccurences.size()); assertEquals(54, line(fromStringOccurences.get(0))); assertEquals(16, column(fromStringOccurences.get(0))); // Test searching of signatures List<SearchResult.Precise> objectAndStringNoCaseOccurrences = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.ALL, Arrays.asList(new QualifiedName[] {CAL_Prelude.TypeConstructors.JObject, CAL_StringNoCase.TypeConstructors.StringNoCase})); assertEquals(4, objectAndStringNoCaseOccurrences.size()); assertEquals(baseLine + 82, line(objectAndStringNoCaseOccurrences.get(0))); assertEquals(20, column(objectAndStringNoCaseOccurrences.get(0))); assertEquals(baseLine + 85, line(objectAndStringNoCaseOccurrences.get(1))); assertEquals(27, column(objectAndStringNoCaseOccurrences.get(1))); assertEquals(baseLine + 86, line(objectAndStringNoCaseOccurrences.get(2))); assertEquals(42, column(objectAndStringNoCaseOccurrences.get(2))); assertEquals(baseLine + 91, line(objectAndStringNoCaseOccurrences.get(3))); assertEquals(28, column(objectAndStringNoCaseOccurrences.get(3))); } /** * Test that search results always come back in source order. * SourceMetricFinder_Test_Support.outOfOrderBinaryExpression and * SourceMetricFinder_Test_Support.outOfOrderBackquotedExpression have been explicitly * constructed to make this test fail if we are traversing the source tree in pre-order * or post-order. */ public void testSearchResultsOrder() { List<SearchResult.Precise> addResults = SourceMetricFinder.performSearch(moduleDefn, moduleTypeInfo, SourceMetricFinder.SearchType.REFERENCES, Collections.singletonList(CAL_Prelude.Functions.add)); assertTrue(addResults.size() > 0); SourcePosition previousPosition = null; for (final SearchResult.Precise preciseResult : addResults) { SourcePosition currentPosition = preciseResult.getSourcePosition(); if(previousPosition != null) { assertTrue(SourcePosition.compareByPosition.compare(previousPosition, currentPosition) < 0); } previousPosition = currentPosition; } List<SearchResult> rootResults = workspaceSourceMetrics.findDefinition("*Call*", new MessageLogger()); assertTrue(rootResults.size() > 0); // Results from a workspace-level find should be both ordered and grouped by module Set<String> previousModules = new HashSet<String>(); previousPosition = null; for (final SearchResult searchResult : rootResults) { SourcePosition currentPosition = ((SearchResult.Precise)searchResult).getSourcePosition(); if(previousPosition != null) { if(previousPosition.getSourceName().equals(currentPosition.getSourceName())) { assertTrue(SourcePosition.compareByPosition.compare(previousPosition, currentPosition) < 0); } else { assertFalse(previousModules.contains(currentPosition.getSourceName())); previousModules.add(currentPosition.getSourceName()); } } previousPosition = currentPosition; } } /** * Test that search is case-insensitive. */ public void testSearchCaseInsensitivity() { MessageLogger messageLogger = new MessageLogger(); List<SearchResult> leafDefns = workspaceSourceMetrics.findDefinition("sourcemetricfinder_test_support.lEaF*", messageLogger); assertTrue(messageLogger.getMaxSeverity().compareTo(CompilerMessage.Severity.INFO) <= 0); assertEquals(9, leafDefns.size()); int i = 0; for(Iterator<SearchResult> it = leafDefns.iterator(); it.hasNext(); i++) { SearchResult searchResult = it.next(); String expectedUnqualifiedName = "leaf" + i; final QualifiedName qn = (QualifiedName) searchResult.getName(); assertTrue(qn.getUnqualifiedName().equals(expectedUnqualifiedName)); assertTrue(qn.getModuleName().equals(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support)); } List<SearchResult> leafReferences = workspaceSourceMetrics.findReferences("sourceMETRICfinder_test_SUPPORT.LeAf?", messageLogger); assertTrue(messageLogger.getMaxSeverity().compareTo(CompilerMessage.Severity.INFO) <= 0); assertEquals(18, leafReferences.size()); int prevNumber = 1; for (final SearchResult searchResult : leafReferences) { final QualifiedName qn = (QualifiedName) searchResult.getName(); assertTrue(qn.getModuleName().equals(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support)); int currentNumber = Integer.parseInt("" + qn.getUnqualifiedName().charAt(4)); assertTrue(currentNumber == prevNumber || currentNumber == prevNumber + 1); prevNumber = currentNumber; } } /** * Test that the search for a foriegn data type returns the correct results. */ public void testSearchForForeignDateType() { MessageLogger messageLogger = new MessageLogger(); List<SearchResult> leafDefns = workspaceSourceMetrics.findDefinition("sourcemetricfinder_test_support.JFile", messageLogger); assertTrue(messageLogger.getMaxSeverity().compareTo(CompilerMessage.Severity.INFO) <= 0); assertEquals(1, leafDefns.size()); int i = 0; for(Iterator<SearchResult> it = leafDefns.iterator(); it.hasNext(); i++) { SearchResult searchResult = it.next(); String expectedUnqualifiedName = "JFile"; final QualifiedName qn = (QualifiedName) searchResult.getName(); assertTrue(qn.getUnqualifiedName().equals(expectedUnqualifiedName)); assertTrue(qn.getModuleName().equals(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support)); } } private static int line(SearchResult.Precise searchResult) { return searchResult.getSourcePosition().getLine(); } private static int column(SearchResult.Precise searchResult) { return searchResult.getSourcePosition().getColumn(); } /** * Helper function; scans a list of warnings for a warning of a given type in a given function. * @param functionName String Function name to look for * @param warningType LintWarning.WarningType Type of warning to look for * @param warningList List (LintWarning) * @return true when warningList contains a warning of type warningType for a function named functionName */ private static boolean functionFlagged(String functionName, LintWarning.WarningType warningType, List<LintWarning> warningList) { for (final LintWarning warning : warningList) { if(warning.getWarningType() == warningType && warning.getFunctionName().getUnqualifiedName().equals(functionName)) { return true; } } return false; } /** * Helper function for looking up the compositional frequency of two private functions in the frequency map. * @param compositionalFrequencyMap Map to look up the frequency from * @param consumerUnqualifiedName Unqualified name of a consumer function in the SourceMetricFinder_Test_Support module * @param producerUnqualifiedName Unqualified name of a producer function in the SourceMetricFinder_Test_Support module * @return If the specified (consumer, producer) pair is a key in the specified map, then returns the associated compositional frequency. * otherwise, returns 0. */ private static int getCompositionalFrequency(Map<Pair<QualifiedName, QualifiedName>, Integer> compositionalFrequencyMap, String consumerUnqualifiedName, String producerUnqualifiedName) { QualifiedName consumerKey = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, consumerUnqualifiedName); QualifiedName producerKey = QualifiedName.make(CALPlatformTestModuleNames.SourceMetricFinder_Test_Support, producerUnqualifiedName); Integer value = compositionalFrequencyMap.get(new Pair<QualifiedName, QualifiedName>(consumerKey, producerKey)); if(value != null) { return value.intValue(); } else { return 0; } } /** * @param moduleSourceDefn The source definition to read the source text for * @return The source text of a module as a single String */ private static String readModuleSource(ModuleSourceDefinition moduleSourceDefn) { Reader reader = moduleSourceDefn.getSourceReader(new Status("reading module source")); if (reader == null) { System.err.println("Failed to read module " + moduleSourceDefn.getModuleName()); return null; } BufferedReader bufferedReader = new BufferedReader(reader); StringBuilder stringBuf = new StringBuilder(); String line = null; try { while ((line = bufferedReader.readLine()) != null) { stringBuf.append(line).append('\n'); } } catch (IOException e) { System.err.println("Failed to read module " + moduleSourceDefn.getModuleName()); return null; } finally { try { bufferedReader.close(); } catch (IOException e) { } } return stringBuf.toString(); } }