Created
June 1, 2014 23:29
-
-
Save zlqhem/dd6ad12eda4374077774 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lge.metr | |
import org.scalacheck.Properties | |
import org.scalacheck.Prop.forAll | |
import org.scalacheck.Prop.BooleanOperators | |
import org.scalacheck.Prop.classify | |
import org.scalacheck.Prop.collect | |
import org.scalacheck.Arbitrary | |
import org.scalacheck.Arbitrary._ | |
import org.scalacheck._ | |
import Gen._ | |
import scala.language.implicitConversions | |
import JavaModel._ | |
object DlocProperty extends Properties("Metr") with MetricCounter { | |
def genIf(sz:Int): Gen[Stmt] = | |
if (sz <= 0) OtherStmt() | |
else for { | |
thenPart <- genStmt(sz/2) | |
elseStmts <- genStmt(sz/2) | |
elsePart <- oneOf(None, Some(elseStmts)) | |
} yield IfStmt(thenPart, elsePart) | |
def genSwitch(sz:Int): Gen[Stmt] = for { | |
n <- choose(sz/3, sz/2) | |
cases <- listOfN(n, genStmt(sz/2)) | |
} yield SwitchStmt(cases) | |
def genLoop(sz:Int): Gen[Stmt] = for { | |
body <- genStmt(sz/2) | |
} yield LoopStmt("keyword", body) | |
def genBlock(sz:Int): Gen[Stmt] = for { | |
n <- choose(sz/3, sz/2) | |
statements <- listOfN(n, genStmt(sz/2)) | |
} yield BlockStmt(statements) | |
def genSync(sz:Int): Gen[Stmt] = for { | |
body <- genStmt(sz/2) | |
} yield SyncStmt(body) | |
def genTry(sz:Int): Gen[Stmt] = for { | |
body <- genStmt(sz/2) | |
catchers <- listOfN(sz/2, genStmt(sz/2)) | |
stmt <- genStmt(sz/2) | |
finalizer <- oneOf(None, Some(stmt)) | |
} yield TryStmt(body, catchers, finalizer) | |
def genStmt(sz:Int): Gen[Stmt] = { | |
if (sz <= 0) const(OtherStmt()) | |
else | |
frequency((3, genIf(sz/2)), (3, genSwitch(sz/2)), (3, genLoop(sz/2)), | |
(3, genBlock(sz/2)), (3, genSync(sz/2)), (3, genTry(sz/2)), | |
(1, const(OtherStmt()))) | |
} | |
def genMethod(sz:Int): Gen[Method] = for { | |
body <- genStmt(sz/2) | |
} yield Method("method", body) | |
def genCtor(sz:Int): Gen[Ctor] = for { | |
body <- genStmt(sz/2) | |
} yield Ctor("ctor", body) | |
implicit def arbExecutable: Arbitrary[Executable] = Arbitrary { | |
def sizedExecutable(sz:Int): Gen[Executable] = | |
oneOf(genMethod(sz/2), genCtor(sz/2)) | |
sized(sz => sizedExecutable(sz)) | |
} | |
implicit def arbStmt: Arbitrary[Stmt] = Arbitrary { | |
sized(sz => genStmt(sz)) | |
} | |
implicit def stmtToExecutable(stmt:Stmt): Executable = { | |
Method("stmt2Method", stmt) | |
} | |
// "모든 메소드에 대해 SLOC >= DLOC 이다. " | |
// excerpt from http://collab.lge.com/main/pages/viewpage.action?pageId=188052210 | |
property(" #1. 모든 메소드에 대해 SLOC >= DLOC 이다.(invariant)") = forAll {(exe:Executable) => | |
sloc(exe) >= dloc(exe) | |
} | |
def codefat(exe:Executable): Double = (sloc(exe) - dloc(exe)) / sloc(exe) | |
// "CodeFat: control flow 상의 decision depth 를 증가시키는 요소들(if/switch-case/while/for/do-while)을 | |
// 코드상의 지방 요소라고 보아, 전체 코드에서 얼마나 지방 요소가 포함되어 있는지 비율로 나타낸 지표" | |
// excerpt from http://collab.lge.com/main/pages/viewpage.action?pageId=188052210 | |
property(" #2. 임의의 statement 에 대해 if 로 감싸면 codefat 이 증가한다.") = forAll {(stmt:Stmt) => | |
def isSlocZero(exe:Executable): Boolean = sloc(exe) == 0 | |
val stmtIfNested = IfStmt(stmt, None) | |
!isSlocZero(stmt) ==> codefat(stmtIfNested) > codefat(stmt) | |
} | |
property(" #3. codefat 은 IF 문이 블락 끝에 추가되는 것 보다 중첩될 때 더 증가한다.") = | |
forAll {(stmt:Stmt) => | |
classify(dloc(stmt) <= 0, "DLOC == 0", "DLOC > 0") { | |
classify(sloc(stmt) <= 0, "SLOC == 0", "SLOC > 0") { | |
val ifNested = IfStmt(stmt,None) | |
val ifAppended = BlockStmt(List(stmt, IfStmt(BlockStmt(List()), None))) | |
codefat(ifNested) >= codefat(ifAppended) | |
}}} | |
property(" #4. dloc 는 Block 문에 대해 분배법칙이 성립한다.") = | |
forAll {(stmt1:Stmt, stmt2:Stmt) => { | |
dloc(stmt1) + dloc(stmt2) == dloc(BlockStmt(List(stmt1, stmt2))) | |
}} | |
// (dloc(stmt1) + dloc(stmt2)) / (sloc(stmt1) + sloc(stmt2)) == | |
// dloc(Block(stmt1 + stmt2)) / sloc(Block(stmt1 + stmt2)) | |
property(" #5. Block distribution over dloc/sloc") = | |
forAll (genStmt(6),genStmt(6)) {(stmt1:Stmt, stmt2:Stmt) => { | |
val sumSloc = sloc(stmt1) + sloc(stmt2) | |
val r1 = dloc(stmt1) / sumSloc | |
val r2 = dloc(stmt2) / sumSloc | |
val dlocBlock = dloc(BlockStmt(List(stmt1, stmt2))) | |
val slocBlock = sloc(BlockStmt(List(stmt1, stmt2))) | |
val ret = r1 + r2 == dlocBlock / slocBlock | |
if (ret == false) { | |
println ("[%s]: %f == %f" format (r1 + r2 == dlocBlock / slocBlock, r1 + r2, dlocBlock / slocBlock)) | |
println ("[%s]: %f (= %f + %f) == %f (= %f / %f) " format (r1 + r2 == dlocBlock / slocBlock, r1 + r2, r1, r2, dlocBlock / slocBlock, dlocBlock, slocBlock)) | |
} | |
ret | |
}} | |
property(" #6. 랜덤방식의 입력값 생성은 3 * n - 5 == 64 을 만족하는 n 을 만들 확률이 매우 낮다.") = | |
forAll {(n:Int) => | |
if (3 * n - 5 == 64) { | |
false | |
} | |
true | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment