Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
tonybaloney committed Jun 5, 2020
2 parents d6558da + 33fbfe3 commit 7295ac5
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 55 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group 'wily'
version '1.0.0'
version '1.0.1'

sourceCompatibility = 1.8
def kotlin_version = "1.3.72"
Expand Down
18 changes: 8 additions & 10 deletions src/main/kotlin/wily/visitors/CyclomaticRecursiveVisitor.kt
Expand Up @@ -2,20 +2,18 @@ package wily.visitors

import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor
import com.jetbrains.python.psi.PyForStatement
import com.jetbrains.python.psi.PyIfStatement
import com.jetbrains.python.psi.PyConditionalExpression
import com.jetbrains.python.psi.PyStatementWithElse

class CyclomaticRecursiveVisitor() : PsiRecursiveElementVisitor() {
var nodeCount : Int = 0
var branchCount : Int = 0

val branchTypes = arrayOf(
PyIfStatement::class.java,
PyForStatement::class.java) // TODO etc.
class CyclomaticRecursiveVisitor : PsiRecursiveElementVisitor() {
private var nodeCount : Int = 0
private var branchCount : Int = 0

override fun visitElement(element: PsiElement) {
nodeCount++
if (branchTypes.contains(element::class.java))

if (element is PyStatementWithElse ||
element is PyConditionalExpression)
branchCount++
super.visitElement(element)
}
Expand Down
7 changes: 5 additions & 2 deletions src/main/kotlin/wily/visitors/HalsteadRecursiveVisitor.kt
Expand Up @@ -5,6 +5,8 @@ import com.intellij.psi.PsiRecursiveElementVisitor
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.elementType
import com.jetbrains.python.psi.PyElement
import com.jetbrains.python.psi.PyExpressionStatement
import com.jetbrains.python.psi.PyStatement
import kotlin.math.log2

class HalsteadRecursiveVisitor : PsiRecursiveElementVisitor() {
Expand All @@ -14,8 +16,9 @@ class HalsteadRecursiveVisitor : PsiRecursiveElementVisitor() {
private var operatorsCount: Int = 0

override fun visitElement(element: PsiElement) {
if (!operators.contains(element.elementType))
this.operators.add(element.elementType)
if (element is PyExpressionStatement || element is PyStatement)
if (!operators.contains(element.elementType))
this.operators.add(element.elementType)
operatorsCount++
if (element is PyElement) {
operandsCount++
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Expand Up @@ -10,6 +10,7 @@
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<depends>com.intellij.modules.python</depends>
<idea-version since-build="201.5985.*" until-build="202.*" />

<extensions defaultExtensionNs="com.intellij">
<localInspection language="Python" enabledByDefault="false" groupName="Wily" hasStaticDescription="true" displayName="Python module complexity inspection" shortName="PythonModuleInspection" implementationClass="wily.inspections.PythonModuleInspection" />
Expand Down
42 changes: 0 additions & 42 deletions src/test/kotlin/wily/TestTask.kt
@@ -1,50 +1,8 @@
package wily

import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.application.ApplicationManager
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import com.jetbrains.python.PythonFileType
import com.jetbrains.python.inspections.PyInspection
import com.jetbrains.python.inspections.PyInspectionVisitor
import com.jetbrains.python.psi.*
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.types.TypeEvalContext
import com.nhaarman.mockitokotlin2.*
import org.jetbrains.annotations.NotNull
import org.mockito.ArgumentMatchers.contains
import org.mockito.Mockito


open class TestTask: BasePlatformTestCase() {
fun <inspector: PyInspection>testCodeAssignmentStatement(code: String, times: Int = 1, check: Checks.CheckType, filename: String = "test.py", instance: inspector){
ApplicationManager.getApplication().runReadAction {
val mockHolder = mock<ProblemsHolder> {
on { registerProblem(any<PsiElement>(), contains(check.Code), anyVararg<LocalQuickFix>()) } doAnswer {}
on { registerProblem(any<PsiElement>(), contains(check.Code), any<ProblemHighlightType>(), anyVararg<LocalQuickFix>()) } doAnswer {}
}
val testFile = this.createLightFile(filename, PythonFileType.INSTANCE.language, code);
val mockLocalSession = mock<LocalInspectionToolSession> {
on { file } doReturn (testFile)
}
assertNotNull(testFile)
val testVisitor = instance.buildVisitor(mockHolder, true, mockLocalSession) as PyInspectionVisitor

val expr: @NotNull MutableCollection<PyAssignmentStatement> = PsiTreeUtil.findChildrenOfType(testFile, PyAssignmentStatement::class.java)
assertNotNull(expr)
expr.forEach { e ->
testVisitor.visitPyAssignmentStatement(e)
}
try {
Mockito.verify(mockHolder, Mockito.times(times)).registerProblem(any<PsiElement>(), contains(check.Code), anyVararg<LocalQuickFix>())
} catch (a: AssertionError){
Mockito.verify(mockHolder, Mockito.times(times)).registerProblem(any<PsiElement>(), contains(check.Code), any<ProblemHighlightType>(), anyVararg<LocalQuickFix>())
}
Mockito.verify(mockLocalSession, Mockito.times(1)).file
}
}
}
103 changes: 103 additions & 0 deletions src/test/kotlin/wily/visitors/CyclomaticRecursiveVisitorTest.kt
@@ -0,0 +1,103 @@
package wily.visitors

import com.intellij.openapi.application.ApplicationManager
import com.jetbrains.python.PythonFileType
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import wily.TestTask

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class CyclomaticRecursiveVisitorTest: TestTask() {

@BeforeAll
override fun setUp() {
super.setUp()
}

@AfterAll
override fun tearDown(){
super.tearDown()
}

private fun visitCode(code: String): CyclomaticRecursiveVisitor {
val visitor = CyclomaticRecursiveVisitor()
ApplicationManager.getApplication().runReadAction {
val testFile = this.createLightFile("test.py", PythonFileType.INSTANCE.language, code);
visitor.visitFile(testFile)
}
return visitor
}

@Test
fun `test zero CC for empty code`(){
val code = """
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 0)
}

@Test
fun `test simple statement`(){
val code = """
a = 1
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 0)
}

@Test
fun `test series of simple statements`(){
val code = """
a = 1
b = 2
c = 3
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 0)
}

@Test
fun `test simple if`(){
val code = """
if a = 1:
pass
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 1)
}

@Test
fun `test nested if`(){
val code = """
if a = 1:
if b = 2:
pass
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 2)
}

@Test
fun `test simple for loop`(){
val code = """
for a in b:
pass
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 1)
}

@Test
fun `test simple while loop`(){
val code = """
while a is True:
pass
""".trimIndent()
val v = visitCode(code)
assertEquals(v.complexity(), 1)
}
}
43 changes: 43 additions & 0 deletions src/test/kotlin/wily/visitors/HalsteadRecursiveVisitorTest.kt
@@ -0,0 +1,43 @@
package wily.visitors

import com.intellij.openapi.application.ApplicationManager
import com.jetbrains.python.PythonFileType
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import wily.TestTask

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class HalsteadRecursiveVisitorTest: TestTask() {

@BeforeAll
override fun setUp() {
super.setUp()
}

@AfterAll
override fun tearDown(){
super.tearDown()
}

private fun visitCode(code: String): HalsteadRecursiveVisitor {
val visitor = HalsteadRecursiveVisitor()
ApplicationManager.getApplication().runReadAction {
val testFile = this.createLightFile("test.py", PythonFileType.INSTANCE.language, code);
visitor.visitFile(testFile)
}
return visitor
}

@Test
fun `test simple statement`(){
val code = """
a = 1
""".trimIndent()
val v = visitCode(code)
assertEquals(v.vocabulary(), 3)
assertEquals(v.length(), 3)
}
}

0 comments on commit 7295ac5

Please sign in to comment.