Skip to content

Commit

Permalink
Implementation of attributeDescriptors, a new json field that describ…
Browse files Browse the repository at this point in the history
…es used metrics (#3091)

* Add draft implementation of attributeDescriptors

#1066

* Refactor Codemaat Tests and code cleanup

* Change readme and doc instructions for codemaat usage

* Add tests to CodeMaat to verify new file content and add equal method

* Refactor Merge Tests

* Refactor equals check

* Add and Refactor Mergefilter Tests for AttributeDescriptor support

* Add AttributeDescriptor support and add tests

* Refactor tests to use junit.jupiter

* Add help function to remove unused attributeDescriptors

* Add removal call for unused descriptors to set-root function

* Add tests for attributeDescriptor handling

* Add test to main class for 'remove' and 'set root' with descriptors

* Add descriptors with tests to SourceMonitor

* Remove spek2 test environment in some places

* Add flag for attributeDescriptor cleanup

* Refactor descriptor removal to terminate faster

* Add attributeDescriptors to gitlog parser with tests

* Add attributeDescriptors to metricgardener with tests

* Add attributeDescriptor test and refactor sm-importer test, so that no files are left behind

* Add changelog entry

* Refactor test names and clear up file names
  • Loading branch information
phanlezz committed Nov 22, 2022
1 parent 291bcd5 commit 5f08ae1
Show file tree
Hide file tree
Showing 60 changed files with 1,174 additions and 612 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

## [unreleased] (Added 🚀 | Changed | Removed 🗑 | Fixed 🐞 | Chore 👨‍💻 👩‍💻)

### Added 🚀

- Add attribute descriptors (metric descriptions) to some filters and importers [#3091](https://github.com/MaibornWolff/codecharta/pull/3091)

## [1.111.0] - 2022-11-17

### Added 🚀
Expand Down
15 changes: 0 additions & 15 deletions analysis/filter/EdgeFilter/build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
repositories {
maven {
url 'https://dl.bintray.com/spekframework/spek-dev'
}
}

dependencies {
implementation project(':model')
implementation project(':tools:InteractiveParser')
Expand All @@ -14,19 +8,10 @@ dependencies {
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlin_logging_version
implementation group: 'com.github.kotlin-inquirer', name: 'kotlin-inquirer', version: kotlin_inquirer_version

implementation group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version

testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: hamcrest_version
testImplementation group: 'org.jetbrains.kotlin', name: 'kotlin-test', version: kotlin_version
testImplementation("org.spekframework.spek2:spek-dsl-jvm:$spek2_version") {
exclude group: 'org.jetbrains.kotlin'
}
testImplementation group: 'org.assertj', name: 'assertj-core', version: assertj_version
testImplementation group: 'io.mockk', name: 'mockk', version: mockk_version

testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:$spek2_version") {
exclude group: 'org.jetbrains.kotlin'
}
testRuntimeOnly group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.maibornwolff.codecharta.filter.edgefilter

import de.maibornwolff.codecharta.model.AttributeDescriptor
import de.maibornwolff.codecharta.model.AttributeType
import de.maibornwolff.codecharta.model.BlacklistItem
import de.maibornwolff.codecharta.model.Edge
import de.maibornwolff.codecharta.model.MutableNode
import de.maibornwolff.codecharta.model.Node
Expand All @@ -16,15 +18,29 @@ class EdgeProjectBuilder(private val project: Project, private val pathSeparator
private val projectBuilder = ProjectBuilder(
listOf(MutableNode("root", NodeType.Folder)),
mutableListOf(),
getAttributeTypes()
getAttributeTypes(),
getAttributeDescriptors(),
getBlacklist()
)

private fun getAttributeTypes(): MutableMap<String, MutableMap<String, AttributeType>> {
val newAttributetypes: MutableMap<String, MutableMap<String, AttributeType>> = mutableMapOf()
val newAttributeTypes: MutableMap<String, MutableMap<String, AttributeType>> = mutableMapOf()
project.attributeTypes.forEach {
newAttributetypes[it.key] = it.value
newAttributeTypes[it.key] = it.value
}
return newAttributetypes
return newAttributeTypes
}

private fun getAttributeDescriptors(): MutableMap<String, AttributeDescriptor> {
val newAttributeDescriptor = mutableMapOf<String, AttributeDescriptor>()
newAttributeDescriptor.putAll(project.attributeDescriptors)
return newAttributeDescriptor
}

private fun getBlacklist(): MutableList<BlacklistItem> {
val newList = mutableListOf<BlacklistItem>()
newList.addAll(project.blacklist)
return newList
}

fun merge(): Project {
Expand Down Expand Up @@ -113,7 +129,7 @@ class EdgeProjectBuilder(private val project: Project, private val pathSeparator
private fun getAttributeKeys(filteredEdges: List<Edge>): MutableList<String> {
val attributeKeys: MutableList<String> = mutableListOf()
filteredEdges.forEach {
it.attributes.forEach { key, _ -> if (!attributeKeys.contains(key)) attributeKeys.add(key) }
it.attributes.forEach { (key, _) -> if (!attributeKeys.contains(key)) attributeKeys.add(key) }
}
return attributeKeys
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,49 @@
package de.maibornwolff.codecharta.filter.edgefilter

import de.maibornwolff.codecharta.model.AttributeDescriptor
import de.maibornwolff.codecharta.model.Node
import de.maibornwolff.codecharta.serialization.ProjectDeserializer
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.io.InputStreamReader

class ProjectMergerTest : Spek({
class ProjectMergerTest {

val TEST_EDGES_JSON_FILE = "coupling.json"
val TEST_EDGES_JSON_FILE_2 = "coupling-empty-nodes.json"
private val TEST_EDGES_JSON_FILE = "coupling.json"
private val TEST_EDGES_JSON_FILE_2 = "coupling-empty-nodes.json"
private val TEST_EDGES_JSON_FILE_3 = "empty-but-descriptors.json"

describe("filter edges as node attributes") {
@Test
fun `should filter edges as node attributes`() {
val originalProject = ProjectDeserializer.deserializeProject(
InputStreamReader(this.javaClass.classLoader.getResourceAsStream(TEST_EDGES_JSON_FILE))
InputStreamReader(this.javaClass.classLoader.getResourceAsStream(TEST_EDGES_JSON_FILE)!!)
)
val project = EdgeProjectBuilder(originalProject, '/').merge()

val parent1 = getChildByName(project.rootNode.children.toMutableList(), "Parent 1")
val parent2 = getChildByName(parent1.children.toMutableList(), "Parent 2")

val leaf1 = getChildByName(project.rootNode.children.toMutableList(), "leaf 1")
val leaf3 = getChildByName(parent1.children.toMutableList(), "leaf 3")
val leaf4 = getChildByName(parent2.children.toMutableList(), "leaf 4")

it("should have correct amount of edges") {
MatcherAssert.assertThat(project.sizeOfEdges(), CoreMatchers.`is`(6))
}
assertEquals(project.sizeOfEdges(), 6)
assertEquals(project.size, 5)
assertEquals(leaf1.attributes.size, 5)

it("should have correct amount of files") {
MatcherAssert.assertThat(project.size, CoreMatchers.`is`(5))
}

it("leaf1 should have correct number of attributes") {
MatcherAssert.assertThat(leaf1.attributes.size, CoreMatchers.`is`(5))
}

it("leaf1 should have correct pairingRate_relative value") {
val value: Int = getAttributeValue(leaf1.attributes, "pairingRate")
val expectedValue = (90 + 30 + 70) / 3 // see testfile
MatcherAssert.assertThat(value, CoreMatchers.`is`(expectedValue))
}

it("leaf1 should have correct avgCommits_absolute value") {
val value: Int = getAttributeValue(leaf1.attributes, "avgCommits")
val expectedValue = 30 + 10 + 30 // see testfile
MatcherAssert.assertThat(value, CoreMatchers.`is`(expectedValue))
}

it("leaf3 should have correct pairingRate_relative value") {
val number: Int = getAttributeValue(leaf3.attributes, "pairingRate")
val expectedValue = (90 + 60 + 70) / 3 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}

it("leaf3 should have correct avgCommits_absolute value") {
val number: Int = getAttributeValue(leaf3.attributes, "avgCommits")
val expectedValue = 30 + 40 + 30 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}

it("leaf4 should have correct pairingRate_relative value") {
val number: Int = getAttributeValue(leaf4.attributes, "pairingRate")
val expectedValue = (60 + 80 + 60) / 3 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}

it("leaf4 should have correct avgCommits_absolute value") {
val number: Int = getAttributeValue(leaf4.attributes, "avgCommits")
val expectedValue = 20 + 30 + 40 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
val leafs = listOf(leaf1, leaf3, leaf4)
// Check test files
val expectedPairingRates = listOf((90 + 30 + 70) / 3, (90 + 60 + 70) / 3, (60 + 80 + 60) / 3)
val expectedAvgCommits = listOf(30 + 10 + 30, 30 + 40 + 30, 20 + 30 + 40)
leafs.forEachIndexed { i, curLeaf ->
assertEquals(getAttributeValue(curLeaf.attributes, "pairingRate"), expectedPairingRates[i])
assertEquals(getAttributeValue(curLeaf.attributes, "avgCommits"), expectedAvgCommits[i])
}
}

describe("filter edges as node attributes with empty nodes list in testfile") {
@Test
fun `should filter edges as node attributes with empty nodes list in testfile`() {
val originalProject = ProjectDeserializer.deserializeProject(
InputStreamReader(this.javaClass.classLoader.getResourceAsStream(TEST_EDGES_JSON_FILE_2))
InputStreamReader(this.javaClass.classLoader.getResourceAsStream(TEST_EDGES_JSON_FILE_2)!!)
)
val project = EdgeProjectBuilder(originalProject, '/').merge()

Expand All @@ -88,59 +54,40 @@ class ProjectMergerTest : Spek({
val leaf3 = getChildByName(parent1.children.toMutableList(), "leaf 3")
val leaf4 = getChildByName(parent2.children.toMutableList(), "leaf 4")

it("should have correct amount of edges") {
MatcherAssert.assertThat(project.sizeOfEdges(), CoreMatchers.`is`(6))
}

it("leaf1 should have correct number of attributes") {
MatcherAssert.assertThat(leaf1.attributes.size, CoreMatchers.`is`(2))
}
assertEquals(project.sizeOfEdges(), 6)
assertEquals(leaf1.attributes.size, 2)

it("leaf1 should have correct pairingRate_relative value") {
val value: Int = getAttributeValue(leaf1.attributes, "pairingRate")
val expectedValue = (90 + 30 + 70) / 3 // see testfile
MatcherAssert.assertThat(value, CoreMatchers.`is`(expectedValue))
}

it("leaf1 should have correct avgCommits_absolute value") {
val value: Int = getAttributeValue(leaf1.attributes, "avgCommits")
val expectedValue = 30 + 10 + 30 // see testfile
MatcherAssert.assertThat(value, CoreMatchers.`is`(expectedValue))
}

it("leaf3 should have correct pairingRate_relative value") {
val number: Int = getAttributeValue(leaf3.attributes, "pairingRate")
val expectedValue = (90 + 60 + 70) / 3 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}

it("leaf3 should have correct avgCommits_absolute value") {
val number: Int = getAttributeValue(leaf3.attributes, "avgCommits")
val expectedValue = 30 + 40 + 30 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}

it("leaf4 should have correct pairingRate_relative value") {
val number: Int = getAttributeValue(leaf4.attributes, "pairingRate")
val expectedValue = (60 + 80 + 60) / 3 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
val leafs = listOf(leaf1, leaf3, leaf4)
// Check test files
val expectedPairingRates = listOf((90 + 30 + 70) / 3, (90 + 60 + 70) / 3, (60 + 80 + 60) / 3)
val expectedAvgCommits = listOf(30 + 10 + 30, 30 + 40 + 30, 20 + 30 + 40)
leafs.forEachIndexed { i, curLeaf ->
assertEquals(getAttributeValue(curLeaf.attributes, "pairingRate"), expectedPairingRates[i])
assertEquals(getAttributeValue(curLeaf.attributes, "avgCommits"), expectedAvgCommits[i])
}
}

it("leaf4 should have correct avgCommits_absolute value") {
val number: Int = getAttributeValue(leaf4.attributes, "avgCommits")
val expectedValue = 20 + 30 + 40 // see testfile
MatcherAssert.assertThat(number, CoreMatchers.`is`(expectedValue))
}
@Test
fun `given a set of attributeDescriptors it should be copied into the new project`() {
val originalProject = ProjectDeserializer.deserializeProject(
InputStreamReader(this.javaClass.classLoader.getResourceAsStream(TEST_EDGES_JSON_FILE_3)!!)
)
val project = EdgeProjectBuilder(originalProject, '/').merge()
val expectedDescriptors = mapOf<String, AttributeDescriptor>(
"Test" to AttributeDescriptor("a", "b", "c", "d"),
"Test2" to AttributeDescriptor("a1", "b2", "c3", "d4")
)
assertEquals(project.attributeDescriptors, expectedDescriptors)
}
})
}

fun getChildByName(children: List<Node>, nodeName: String): Node {
private fun getChildByName(children: List<Node>, nodeName: String): Node {
children.forEach {
if (it.name == nodeName) return it
}
return Node(nodeName)
}

fun getAttributeValue(attributes: Map<String, Any>, attributeName: String): Int {
private fun getAttributeValue(attributes: Map<String, Any>, attributeName: String): Int {
return attributes.filterKeys { s: String -> s == attributeName }[attributeName].toString().toInt()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"projectName": "Sample Project with Edges",
"apiVersion": "1.0",
"nodes": [
{
"name": "root",
"type": "Folder",
"attributes": {},
"children": []
}
],
"edges": [
{
"fromNodeName": "/root/leaf 1",
"toNodeName": "/root/Parent 1/leaf 3",
"attributes": {
"pairingRate": 90,
"avgCommits": 30
}
},
{
"fromNodeName": "/root/leaf 1",
"toNodeName": "/root/leaf 2",
"attributes": {
"pairingRate": 30,
"avgCommits": 10
}
},
{
"fromNodeName": "/root/Parent 1/Parent 2/leaf 4",
"toNodeName": "/root/leaf 2",
"attributes": {
"pairingRate": 60,
"avgCommits": 20
}
},
{
"fromNodeName": "/root/Parent 1/Parent 2/leaf 5",
"toNodeName": "/root/Parent 1/Parent 2/leaf 4",
"attributes": {
"pairingRate": 80,
"avgCommits": 30
}
},
{
"fromNodeName": "/root/Parent 1/Parent 2/leaf 4",
"toNodeName": "/root/Parent 1/leaf 3",
"attributes": {
"pairingRate": 60,
"avgCommits": 40
}
},
{
"fromNodeName": "/root/Parent 1/leaf 3",
"toNodeName": "/root/leaf 1",
"attributes": {
"pairingRate": 70,
"avgCommits": 30
}
}
],
"attributeTypes": {
"nodes": {
"rloc": "absolute",
"functions": "absolute",
"mcc": "absolute"
},
"edges": {
"pairingRate": "relative",
"avgCommits": "absolute"
}
},
"attributeDescriptors": {
"Test": {
"description": "a",
"hintLowValue": "b",
"hintHighValue": "c",
"link": "d"
},
"Test2": {
"description": "a1",
"hintLowValue": "b2",
"hintHighValue": "c3",
"link": "d4"
}
}
}

0 comments on commit 5f08ae1

Please sign in to comment.