Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#118 LCC metric has impediments #236

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/main/java/org/jpeek/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@
* @checkstyle MethodLengthCheck (500 lines)
* @checkstyle JavaNCSSCheck (500 lines)
*
* @todo #9:30min LCC metric has impediments (see puzzles in LCC.xml).
* @todo #9:30min LCC metric has impediments (see puzzles in LCC.xsl).
* Once they are resolved, cover the metric with autotests and add it
* to reports list.
* (details on how to test the metrics are to be negotiated here - #107)
*
* @todo #17:30min MWE metric has impediments (see puzzles in MWE.xml).
* @todo #17:30min MWE metric has impediments (see puzzles in MWE.xsl).
* Once they are resolved, cover the metric with autotests and add it
* to reports list.
* (details on how to test the metrics are to be negotiated here - #107)
Expand Down Expand Up @@ -124,7 +124,8 @@ public App(final Path source, final Path target) {
new MapEntry<>("MMAC", true),
new MapEntry<>("OCC", true),
new MapEntry<>("PCC", true),
new MapEntry<>("TCC", true)
new MapEntry<>("TCC", true),
new MapEntry<>("LCC", true)
)
);
}
Expand Down Expand Up @@ -257,6 +258,14 @@ public void analyze() throws IOException {
)
);
}
if (this.params.containsKey("LCC")) {
reports.add(
new Report(
chain.transform(skeleton),
"LCC"
)
);
}
new IoCheckedScalar<>(
new AndInThreads(
report -> {
Expand Down
25 changes: 15 additions & 10 deletions src/main/resources/org/jpeek/metrics/LCC.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,35 @@ SOFTWARE.
<xsl:template match="skeleton">
<metric>
<xsl:apply-templates select="@*"/>
<title>TCC</title>
<title>LCC</title>
<description>
<xsl:text>LCC(C) = (NDC(C) + NIC(C)) / NP(C), where C is the class, NP(C) is a
maximal possible number of direct or indirect connections - N * (N - 1) / 2,
NDC(C) is a number of direct connections, NID(C) is a number of indirect
connections. Value of the metric is in range [0, 1], greater is better.
NDC(C) is a number of direct connections,
NIC(C) is a number of indirect connections.
Value of the metric is in range [0, 1], greater is better.
</xsl:text>
</description>
<xsl:apply-templates select="node()"/>
</metric>
</xsl:template>
<xsl:template match="class">
<xsl:variable name="methods" select="methods/method"/>
<xsl:variable name="attrs" select="attributes/attribute[@static='false']/text()"/>
<xsl:variable name="methods" select="methods/method[@abstract='false' and @ctor='false']"/>
<xsl:variable name="methods_count" select="count($methods)"/>
<xsl:variable name="NC" select="$methods_count * ($methods_count - 1) div 2"/>
<xsl:variable name="directly-related-pairs">
<xsl:for-each select="$methods">
<xsl:variable name="i" select="position()"/>
<xsl:variable name="left" select="."/>
<xsl:variable name="left_ops" select="$left/ops/op[@code='get' or @code='put']"/>
<xsl:variable name="left_attrs" select="$attrs[. = $left/ops/op/text()]"/>
<xsl:for-each select="$methods">
<xsl:if test="position() &gt; $i">
<xsl:variable name="right" select="."/>
<xsl:variable name="right_ops" select="$right/ops/op[@code='get' or @code='put']"/>
<pair>
<xsl:value-of select="count($left_ops[.=$right_ops])"/>
</pair>
<xsl:variable name="right_attrs" select="$attrs[. = $right/ops/op/text()]"/>
<xsl:if test="exists($left_attrs[. = $right_attrs])">
<pair/>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
Expand All @@ -70,8 +72,8 @@ SOFTWARE.
</xsl:variable>
<xsl:variable name="NIC" select="count($indirectly-related-pairs)"/>
-->
<xsl:variable name="NDC" select="count($directly-related-pairs)"/>
<xsl:variable name="NIC" select="0"/>
<xsl:variable name="NDC" select="count($directly-related-pairs/pair)"/>
<xsl:copy>
<xsl:attribute name="value">
<xsl:choose>
Expand All @@ -86,6 +88,9 @@ SOFTWARE.
</xsl:attribute>
<xsl:apply-templates select="@*"/>
<vars>
<var id="attributes">
<xsl:value-of select="count($attrs)"/>
</var>
<var id="methods">
<xsl:value-of select="count($methods)"/>
</var>
Expand Down
7 changes: 4 additions & 3 deletions src/main/resources/org/jpeek/metrics/TCC.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ SOFTWARE.
<description>
<xsl:text>TCC(C) = NDC(C) / NP(C), where C is the class, NP(C) is a
maximal possible number of direct or indirect connections - N * (N - 1) / 2,
NDC(C) is a number of direct connections. Value of the metric is in range [0, 1],
greater is better.
NDC(C) is a number of direct connections.
Value of the metric is in range [0, 1], greater is better.
</xsl:text>
</description>
<xsl:apply-templates select="node()"/>
Expand Down Expand Up @@ -80,7 +80,8 @@ SOFTWARE.
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$NDC div $NC"/>
<xsl:variable name="tcc" select="$NDC div $NC"/>
<xsl:value-of select="format-number($tcc, '0.####')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
Expand Down
81 changes: 49 additions & 32 deletions src/test/java/org/jpeek/MetricsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,20 @@ public final class MetricsTest {
@Parameterized.Parameters(name = "{0}:{1}:{2}")
public static Collection<Object[]> targets() {
return new CollectionOf<>(
new Object[] {"NoMethods", "NHD", Double.NaN},
new Object[] {"Bar", "CAMC", 0.4d},
new Object[] {"Foo", "CAMC", 0.6667d},
new Object[] {"MethodsWithDiffParamTypes", "CCM", 0.0476d},
new Object[] {"Bar", "LCC", 0.0d},
new Object[] {"Foo", "LCC", 1.0d},
new Object[] {"MethodMethodCalls", "LCC", 0.1d},
new Object[] {"MethodsWithDiffParamTypes", "LCC", 0.2d},
new Object[] {"NoMethods", "LCC", 0.0d},
new Object[] {"OneMethodCreatesLambda", "LCC", 0.0d},
new Object[] {"OneVoidMethodWithoutParams", "LCC", 0.0d},
new Object[] {"OnlyOneMethodWithParams", "LCC", 0.0d},
new Object[] {"OverloadMethods", "LCC", 1.0d},
new Object[] {"TwoCommonAttributes", "LCC", 0.0d},
new Object[] {"WithoutAttributes", "LCC", 0.0d},
new Object[] {"Bar", "LCOM", 6.0d},
new Object[] {"Foo", "LCOM", 1.0d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM", 15.0d},
Expand All @@ -97,8 +110,31 @@ public static Collection<Object[]> targets() {
new Object[] {"TwoCommonAttributes", "LCOM", 6.0d},
new Object[] {"WithoutAttributes", "LCOM", 1.0d},
new Object[] {"OneMethodCreatesLambda", "LCOM", 3.0d},
new Object[] {"Bar", "CAMC", 0.4d},
new Object[] {"Foo", "CAMC", 0.6667d},
new Object[] {"Foo", "LCOM2", 0.3333d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM2", 0.5714d},
new Object[] {"NoMethods", "LCOM2", 1.0d},
new Object[] {"OneVoidMethodWithoutParams", "LCOM2", 0.5d},
new Object[] {"OverloadMethods", "LCOM2", 0.2d},
new Object[] {"TwoCommonAttributes", "LCOM2", 0.75d},
new Object[] {"WithoutAttributes", "LCOM2", 0.0d},
new Object[] {"OneMethodCreatesLambda", "LCOM2", 1.0d},
new Object[] {"Foo", "LCOM3", 0.5d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM3", 0.6667d},
new Object[] {"NoMethods", "LCOM3", 0.0d},
new Object[] {"OneVoidMethodWithoutParams", "LCOM3", 1.0d},
new Object[] {"OverloadMethods", "LCOM3", 0.25d},
new Object[] {"TwoCommonAttributes", "LCOM3", 1.0d},
new Object[] {"WithoutAttributes", "LCOM3", 0.0d},
new Object[] {"MethodMethodCalls", "LCOM4", 0.6d},
new Object[] {"Bar", "LCOM5", 0.8125d},
new Object[] {"Foo", "LCOM5", 0.5d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM5", 0.6667d},
new Object[] {"OverloadMethods", "LCOM5", 0.25d},
new Object[] {"TwoCommonAttributes", "LCOM5", 1.0d},
new Object[] {"NoMethods", "LCOM5", Double.NaN},
new Object[] {"WithoutAttributes", "LCOM5", Double.NaN},
new Object[] {"OneVoidMethodWithoutParams", "LCOM5", 1.0d},
new Object[] {"OneMethodCreatesLambda", "LCOM5", 1.5d},
new Object[] {"Bar", "MMAC", 0.1d},
new Object[] {"Foo", "MMAC", 0.3333d},
new Object[] {"MethodsWithDiffParamTypes", "MMAC", 0.0d},
Expand All @@ -108,46 +144,28 @@ public static Collection<Object[]> targets() {
new Object[] {"TwoCommonAttributes", "MMAC", 0.1667d},
new Object[] {"WithoutAttributes", "MMAC", 0.0d},
new Object[] {"OneMethodCreatesLambda", "MMAC", 0.0d},
new Object[] {"Foo", "LCOM5", 0.5d},
new Object[] {"Bar", "LCOM5", 0.8125d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM5", 0.6667d},
new Object[] {"OverloadMethods", "LCOM5", 0.25d},
new Object[] {"TwoCommonAttributes", "LCOM5", 1.0d},
new Object[] {"NoMethods", "LCOM5", Double.NaN},
new Object[] {"WithoutAttributes", "LCOM5", Double.NaN},
new Object[] {"OneVoidMethodWithoutParams", "LCOM5", 1.0d},
new Object[] {"OneMethodCreatesLambda", "LCOM5", 1.5d},
new Object[] {"Bar", "NHD", 0.4d},
new Object[] {"Foo", "NHD", 0.3333d},
new Object[] {"MethodsWithDiffParamTypes", "NHD", 0.7143d},
new Object[] {"OverloadMethods", "NHD", 0.5333d},
new Object[] {"TwoCommonAttributes", "NHD", 0.3333d},
new Object[] {"MethodsWithDiffParamTypes", "CCM", 0.0476d},
new Object[] {"NoMethods", "NHD", Double.NaN},
new Object[] {"Foo", "OCC", 0.5d},
new Object[] {"MethodsWithDiffParamTypes", "PCC", 0.3333d},
new Object[] {"TwoCommonAttributes", "SCOM", 0.0d},
new Object[] {"NoMethods", "SCOM", Double.NaN},
new Object[] {"OneVoidMethodWithoutParams", "SCOM", 0.0d},
new Object[] {"WithoutAttributes", "SCOM", Double.NaN},
new Object[] {"OneMethodCreatesLambda", "SCOM", 0.0d},
new Object[] {"Foo", "LCOM2", 0.3333d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM2", 0.5714d},
new Object[] {"NoMethods", "LCOM2", 1.0d},
new Object[] {"OneVoidMethodWithoutParams", "LCOM2", 0.5d},
new Object[] {"OverloadMethods", "LCOM2", 0.2d},
new Object[] {"TwoCommonAttributes", "LCOM2", 0.75d},
new Object[] {"WithoutAttributes", "LCOM2", 0.0d},
new Object[] {"OneMethodCreatesLambda", "LCOM2", 1.0d},
new Object[] {"Foo", "LCOM3", 0.5d},
new Object[] {"MethodsWithDiffParamTypes", "LCOM3", 0.6667d},
new Object[] {"NoMethods", "LCOM3", 0.0d},
new Object[] {"OneVoidMethodWithoutParams", "LCOM3", 1.0d},
new Object[] {"OverloadMethods", "LCOM3", 0.25d},
new Object[] {"TwoCommonAttributes", "LCOM3", 1.0d},
new Object[] {"WithoutAttributes", "LCOM3", 0.0d},
new Object[] {"MethodsWithDiffParamTypes", "PCC", 0.3333d},
new Object[] {"Foo", "OCC", 0.5d},
new Object[] {"Bar", "TCC", 0.0d},
new Object[] {"Foo", "TCC", 1.0d},
new Object[] {"IndirectlyRelatedPairs", "TCC", 0.6667},
new Object[] {"MethodMethodCalls", "TCC", 0.1d},
new Object[] {"MethodsWithDiffParamTypes", "TCC", 0.2d},
new Object[] {"NoMethods", "TCC", 0.0d},
new Object[] {"OneMethodCreatesLambda", "TCC", 0.0d},
new Object[] {"OneVoidMethodWithoutParams", "TCC", 0.0d},
new Object[] {"OnlyOneMethodWithParams", "TCC", 0.0d},
new Object[] {"OverloadMethods", "TCC", 1.0d},
new Object[] {"TwoCommonAttributes", "TCC", 0.0d},
new Object[] {"WithoutAttributes", "TCC", 0.0d},
Expand All @@ -158,8 +176,7 @@ public static Collection<Object[]> targets() {
new Object[] {"OnlyOneMethodWithParams", "TLCOM", 0.0d},
new Object[] {"OverloadMethods", "TLCOM", 0.0d},
new Object[] {"TwoCommonAttributes", "TLCOM", 4.0d},
new Object[] {"WithoutAttributes", "TLCOM", 1.0d},
new Object[] {"MethodMethodCalls", "LCOM4", 0.6d}
new Object[] {"WithoutAttributes", "TLCOM", 1.0d}
);
}

Expand Down
15 changes: 15 additions & 0 deletions src/test/resources/org/jpeek/samples/IndirectlyRelatedPairs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
public final class IndirectlyRelatedPairs {
int a, b, c, d;
public IndirectlyRelatedPairs(final int x) {
methodOne(a+d);
}
public void methodOne(final int x) {
methodTwo(a+b);
}
public void methodTwo(final int x) {
methodThree(b+c);
}
public void methodThree(final int x) {
new IndirectlyRelatedPairs(c+d);
}
}