---
# System prepended metadata

title: Gzoltar 使用方法
tags: [ncyu_lab]

---

# Gzoltar 使用方法

> 建議虛擬機設定16GB的RAM，不然Gzoltar在執行較大的檔案，如Closure會因為OutOfMemory而錯誤


## 環境設定

下載SimFix
```
git clone https://github.com/xgdsmileboy/SimFix.git
```

下載GZoltar
```
git clone https://github.com/GZoltar/gzoltar.git
```

最後的 "bashrc" 檔案會在後面加這些。
```
export JAVA_HOME=/opt/JDK/jdk1.7.0_80
#export JAVA_HOME=/opt/JDK/jdk1.8.0_401
export PATH=$JAVA_HOME/bin:$PATH

export ANT_HOME=/opt/ANT/apache-ant-1.9.16
export PATH=$ANT_HOME/bin:$PATH

#defects4j path
export PATH=$PATH:~/defects4j/framework/bin
export DEFECTS4J_HOME=~/defects4j

export GZOLTAR_JAR='~/SimFix/sbfl/gzoltar/gzoltar.jar'
```

gzoltar切換至要使用的版本(以v1.7.2為例)，並確認切換正確。
> 目前gzoltar最新版本為1.7.3，也可以選擇不切版本直接使用，此工具不影響matrix結果。
> 但請注意如果使用v1.7.3，後續的腳本要自行更改。
```
cd gzoltar
git checkout v1.7.2
git describe --tags
```

## 實際操作方式

### step 1
* 輸入下列指令打包，在打包之前要先到 "bashrc" 切換成java1.8，不然會報錯。
```
export JAVA_HOME=/opt/JDK/jdk1.8.0_401
```

### step 2
請檢查~/gzoltar/ 底下任一資料夾是否都存在target資料夾。
如果沒有，請在terminal上執行下面指令。
```
cd ~/gzoltar/
mvn -e -X -DskipTests clean package | tee build.log
```

### step 3
自動抓出所有的src位置與test名稱，用於後續GZoltar使用。
這裡還是使用自己另外抓的defects4j，不是SimFix的。
在"Home"目錄下 新增一個sh檔案"auto_arc_text.sh" ，完成後執行。
```
touch auto_arc_text.sh
```

> 20250520更新
> 在每個錯誤版本的資料夾使用此指令就能抓出來了，再把它放到相對應的位置
> 因為math有點不一樣，所以用find的指令找出test會有問題
> `defects4j export -p tests.all`
> 所以之後把find test的部分修改

將下面內容貼入auto_arc_text.sh中

:::spoiler auto_arc_text.sh

```
#!/bin/bash

# ----------------------------------------
# 以下是需要手動修改的部分
# 修改這裡的 defects4j 將project的資料抓下來的位置
# 每個人抓下來的位置都不同
user_def_path=~/d4j_project/

# 這裡是src_path的位置，此為SimFix提供，表示Defects4J的原始碼與測試檔案的路徑
# 建議能從SimFix提供的檔案取得，位置在SimFix/d4j-nfo/src_path
# 每個人抓下來的位置都不同
src_path=~/src_path/

# 針對的專案
# 更改處理成其他的專案要修改，例如，closure，Num是133個。
# 並且記得建立"src_and_test_folder"資料夾的部分要記得刪除。
proj2=chart
Num=26
# ----------------------------------------

# 建立資料夾名為 src_and_test_folder
mkdir src_and_test_folder

echo "資料夾 'src_and_test_folder' 已建立。"

cd src_and_test_folder

# 建立存放各個project的詳細測試與src檔案。
mkdir ${proj2}
echo "資料夾 '${proj2}' 已建立。"
cd ${proj2}

for bug_id in $(seq 1 ${Num})
do
    mkdir ${proj2}_${bug_id}_buggy
    mess=${proj2}_${bug_id}_buggy
    echo "資料夾 '${mess}' 已建立。"
    
    cd ${mess}
    > src.txt #防呆初始化，怕出事
    > test.txt #防呆初始化，怕出事
    
    # 取得src_path檔案位置
    src_path_locate=${src_path}${proj2}/${bug_id}.txt
    #echo "檔案位置： '${src_path_locate}'"
    source=$(head -n 1 "$src_path_locate")
    #echo "source code 位置： '${source}'"
    test_path=$(head -n 3 "$src_path_locate" | tail -n 1)
    #echo "test code 位置： '${test_path}'"
    
    #這邊需要看不同的專案，他所讀取的位置
    #例如Chart的位置，我是放在/
    /ncyu/d4j_project/chart/chart_x_buggy中，所以後面就要加上專案的build與test資料夾
    #find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/source/org -name *.java >> src.txt
    find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy${source} -name *.java >> src.txt
    
    # 移動到對應的defects4J資料夾
    cd ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy
    # 處理成GZoltar看得懂的格式。
    defects4j export -p tests.all >> ~/src_and_test_folder/${proj2}/${proj2}_${bug_id}_buggy/test.txt
    
    #這個格式gzoltar看不懂，所以註解
    #find ${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/org -name *.java >> test.txt
    # 處理成GZoltar看得懂的格式。
    # 這個格式在其他的專案有問題，所以改成defects4J提供的方法。
    #find "${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests" -type f -name "*Tests*" | sed "s|${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/||; s|/|.|g; s|\.java$||" > test.txt
    #find "${user_def_path}${proj2}/${proj2}_${bug_id}_buggy${test_path}" -type f -name "*Tests*" | sed "s|${user_def_path}${proj2}/${proj2}_${bug_id}_buggy/tests/||; s|/|.|g; s|\.java$||" > test.txt
    
    # 回到"src_and_test_folder/Chart"
    cd ~/src_and_test_folder/${proj2}
done

cd ..

# ----------------------------------------
# 如果需要新增其他專案資料夾，請在此處添加
# 例如：mkdir Closure
# ----------------------------------------
```

:::

注意在執行前要先到~/SimFix/d4j-info/ 底下將src_path資料夾完整複製至Home底下，否則會顯示not found file。
```
chmod +x auto_arc_text.sh
./auto_arc_text.sh
```

### step 4
寫一個腳本自動執行不同錯誤定位的結果。
此腳本放在gzoltar資料夾中"test_gzoltar.sh"
這是一次處理chart的部分。

 :::spoiler chart_test_gzoltar.sh

```
SCRIPT_DIR=$(pwd)

#PID=$chart
#BID=$2
#PID=chart
#PID2=Chart
#BID=1
# ------------------
# 自己的defects4j的git clone位置在哪裡。
D4J_HOME=~/defects4j

# 資料集檔案位置
# 此處需要自行修正。
D4J_DIR=~/d4j_project/

# GZoltar的主程式路徑。
# 每個人都不一樣，記得更改(路徑和版本)。
GZOLTAR_AGENT_JAR=~/gzoltar/com.gzoltar.agent.rt/target/com.gzoltar.agent.rt-1.7.2-all.jar
GZOLTAR_CLI_JAR=~/gzoltar/com.gzoltar.cli/target/com.gzoltar.cli-1.7.2-jar-with-dependencies.jar

# 這裡是src_path的位置，此為SimFix提供，表示Defects4J的原始碼與測試檔案的路徑
# 建議能從SimFix提供的檔案取得，位置在SimFix/d4j-nfo/src_path
# 每個人抓下來的位置都不同
src_path=~/src_path/

# 要使用的SBFL公式，目前可使用為：ochiai、jaccard、dstar(這部分還不確定英文要怎麼打，之續需要再確認)
# 根據他們的網站，應該是會自動轉成大寫：https://gzoltar.com/web/javadoc/1.7.2/com/gzoltar/sfl/SFLFormulas.html。
# 不過不確定，需要再釐清。
sfll=ochiai

# 使用的專案以及錯誤版本
pre_PID=chart
pre_PID2=Chart
Num=26

# GZoltar失敗的版本紀錄。
ERROR_LOG=~/gzoltar/${pre_PID}_error_log.txt
# ------------------

GZoltar() {

# 取得錯誤版本以及專案參數
local BID=$1
local PID=$2
local PID2=$3

# ------------------
# 檔案位置
# 此處需要自行修正，自己的Defects4j當初拉到哪個資料夾。
PROJECT_DIR=~/d4j_project/${PID}/${PID}_${BID}_buggy
# ------------------
# 
# 移動到要錯誤定位的檔案位置，例如Chart-1的檔案存放在哪裡。
cd ${PROJECT_DIR}

# 取得src_path檔案位置
src_path_locate=${src_path}${PID}/${BID}.txt
echo "檔案位置： '${src_path_locate}'"
build_path=$(head -n 2 "$src_path_locate" | tail -n 1)
echo "source code 位置： '${build_path}'"
build_test_path=$(head -n 4 "$src_path_locate" | tail -n 1)
echo "test code 位置： '${build_test_path}'"

# Checkout defects4j project
# 這是defects4j經過compile之後的結果檔案，自己輸入，因為低版本的好像有問題。
SRC_DIR=${PROJECT_DIR}${build_path}
echo "SRC_DIR 位置： '${SRC_DIR}'"
TEST_DIR=${PROJECT_DIR}${build_test_path}
echo "TEST_DIR 位置： '${TEST_DIR}'"
LIB_DIR=$(~/defects4j/framework/bin/defects4j export -p cp.test)

# 因為defectsj是使用1.7的java，而GZoltar是使用java1.8
# 所以預設bashrc使用java1.7，要執行java1.8的時候就直接export，不要寫在bashrc中。
export JAVA_HOME=/opt/JDK8/jdk1.8.0_401
export PATH=$JAVA_HOME/bin:$PATH

# FIXME: Change Test Data Here!
# 這是剛剛的auto_arc_text.sh所產生的檔案位置，要自己修改。
TEST_DATA=~/src_and_test_folder/${PID}/${PID}_${BID}_buggy/test.txt
# 這一個處理方式用RELEVANT_TESTS提供的修改。
TEST_DATA=$(cat ${TEST_DATA} | sed 's/$/#*/' | sed ':a;N;$!ba;s/\n/:/g')

# List test methods
# output為輸出結果。
# includes為要輸入的檔案是什麼。
java -cp ${LIB_DIR}:${GZOLTAR_CLI_JAR} \
  com.gzoltar.cli.Main listTestMethods \
  ${TEST_DIR} \
  --outputFile ${PROJECT_DIR}/listTestMethods.txt \
  --includes ${TEST_DATA}

# 這邊是相關資料丟到Defects4J的資料夾中，所以預計先等Defects4J抓好後先備份到Nas上。
# 可能不同GZoltar的結果都放一份。
SER_FILE=${PROJECT_DIR}/gzoltar.ser
LOADED_CLASSES_FILE=${D4J_HOME}/framework/projects/${PID2}/loaded_classes/${BID}.src
NORMAL_CLASSES=$(cat ${LOADED_CLASSES_FILE} | sed 's/$/:/' | sed ':a;N;$!ba;s/\n//g')
INNER_CLASSES=$(cat ${LOADED_CLASSES_FILE} | sed 's/$/$*:/' | sed ':a;N;$!ba;s/\n//g')
LOADED_CLASSES=${NORMAL_CLASSES}${INNER_CLASSES}

# Generate .ser file
# 產生覆蓋資訊的步驟
java -javaagent:${GZOLTAR_AGENT_JAR}=destfile=${SER_FILE},buildlocation=${SRC_DIR},includes=${LOADED_CLASSES},excludes="",inclnolocationclasses=false,output="file" \
  -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \
  com.gzoltar.cli.Main runTestMethods \
  --testMethods ${PROJECT_DIR}/listTestMethods.txt \
  --collectCoverage 

# Generate report
# family -> 輸出資料的資料夾名稱
# formula -> 使用的SBFL公式，官網有提供能用哪些SBFL公式，例如可以改成"jaccard"。
# family -> 只能使用"sfl"這個名稱，不然會報錯。
java -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \
  com.gzoltar.cli.Main faultLocalizationReport \
    --buildLocation ${SRC_DIR} \
    --granularity line \
    --inclPublicMethods \
    --inclStaticConstructors \
    --inclDeprecatedMethods \
    --dataFile ${SER_FILE} \
    --outputDirectory ${PROJECT_DIR} \
    --family sfl \
    --formula ${sfll} \
    --metric entropy \
    --formatter txt
}


for bug_id in $(seq 1 ${Num})
do
    export JAVA_HOME=/opt/JDK/jdk1.7.0_80
    export PATH=$JAVA_HOME/bin:$PATH
    GZoltar ${bug_id} ${pre_PID} ${pre_PID2}
    echo "GZoltar針對專案：'${pre_PID}'_'${bug_id}'，使用的公式為：'${sfll}'，已完成"
    
    # 檢查 RANK_DIR 這個 sfl 資料夾是否存在。
    # 記錄用，不確定有沒有用，等等要再確認。
    RANK_DIR=${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/sfl
    if [ -d "$RANK_DIR" ]; then
        echo "排名結果資料夾存在: $RANK_DIR" >> "$ERROR_LOG"  # 將錯誤訊息寫入日誌檔案
    else
        # echo "排名結果資料夾不存在: $RANK_DIR" >> "$ERROR_LOG"  # 將錯誤訊息寫入日誌檔案
        echo "排名結果錯誤版本不存在: $pre_PID_${bug_id} 不存在" >> "$ERROR_LOG"
    fi
done
```

:::

這是一次處理math與lang的部分。
> 這是因為虛擬機RAM設定太小而導致Closure的錯誤後的處理。
> 有使用到shell的list用在for中的操作。

:::spoiler math_lang_test_gzoltar.sh

```
SCRIPT_DIR=$(pwd)

# ------------------
# 自己的defects4j的git clone位置在哪裡。
D4J_HOME=~/defects4j

# GZoltar的主程式路徑。
# 每個人都不一樣，記得更改。
GZOLTAR_AGENT_JAR=~/gzoltar/com.gzoltar.agent.rt/target/com.gzoltar.agent.rt-1.7.2-all.jar
GZOLTAR_CLI_JAR=~/gzoltar/com.gzoltar.cli/target/com.gzoltar.cli-1.7.2-jar-with-dependencies.jar

# 這裡是src_path的位置，此為SimFix提供，表示Defects4J的原始碼與測試檔案的路徑
# 建議能從SimFix提供的檔案取得，位置在SimFix/d4j-nfo/src_path
# 每個人抓下來的位置都不同
src_path=~/src_path/

# 要使用的SBFL公式，目前可使用為：ochiai、jaccard、dstar(這部分還不確定英文要怎麼打，之續需要再確認)
# 根據他們的網站，應該是會自動轉成大寫：https://gzoltar.com/web/javadoc/1.7.2/com/gzoltar/sfl/SFLFormulas.html。
# 不過不確定，需要再釐清。
sfll=jaccard

# 使用的專案以及錯誤版本
pre_PID=closure
pre_PID2=Closure
# 這邊手動輸入版本，針對Closure的修正
# 將需要的特定數字放入一個陣列
bug_ids=(3 13 16 26 29 36 59 60 107 108 110 112 114 115 116 117 118 119 120 121 125 129)
# ------------------

GZoltar() {

# 取得錯誤版本以及專案參數
local BID=$1
local PID=$2
local PID2=$3

# ------------------
# 檔案位置
# 此處需要自行修正，自己的Defects4j當初拉到哪個資料夾。
PROJECT_DIR=~/d4j_project/${PID}/${PID}_${BID}_buggy

# 設置 JAVA_OPTS
#export JAVA_OPTS="-Xms4096m -Xmx4096m -XX:-UseGCOverheadLimit"
export JAVA_OPTS="-Xms4096m -Xmx4096m"
# ------------------
# 
# 移動到要錯誤定位的檔案位置，例如Chart-1的檔案存放在哪裡。
cd ${PROJECT_DIR}

# 取得src_path檔案位置
src_path_locate=${src_path}${PID}/${BID}.txt
echo "檔案位置： '${src_path_locate}'"
build_path=$(head -n 2 "$src_path_locate" | tail -n 1)
echo "source code 位置： '${build_path}'"
build_test_path=$(head -n 4 "$src_path_locate" | tail -n 1)
echo "test code 位置： '${build_test_path}'"

# Checkout defects4j project
# 這是defects4j經過compile之後的結果檔案，自己輸入，因為低版本的好像有問題。
SRC_DIR=${PROJECT_DIR}${build_path}
echo "SRC_DIR 位置： '${SRC_DIR}'"
TEST_DIR=${PROJECT_DIR}${build_test_path}
echo "TEST_DIR 位置： '${TEST_DIR}'"
LIB_DIR=$(~/defects4j/framework/bin/defects4j export -p cp.test)

# 因為defectsj是使用1.7的java，而GZoltar是使用java1.8
# 所以預設bashrc使用java1.7，要執行java1.8的時候就直接export，不要寫在bashrc中。
export JAVA_HOME=/opt/JDK8/jdk1.8.0_401
export PATH=$JAVA_HOME/bin:$PATH


SER_FILE=${PROJECT_DIR}/gzoltar.ser

# Generate report
# family -> 輸出資料的資料夾名稱
# formula -> 使用的SBFL公式，官網有提供能用哪些SBFL公式，例如可以改成"jaccard"。
# family -> 只能使用"sfl"這個名稱，不然會報錯。
java -cp ${GZOLTAR_CLI_JAR}:${LIB_DIR} \
  com.gzoltar.cli.Main faultLocalizationReport \
    --buildLocation ${SRC_DIR} \
    --granularity line \
    --inclPublicMethods \
    --inclStaticConstructors \
    --inclDeprecatedMethods \
    --dataFile ${SER_FILE} \
    --outputDirectory ${PROJECT_DIR} \
    --family sfl \
    --formula ${sfll} \
    --metric entropy \
    --formatter txt
}

# 使用for迴圈遍歷特定數字
for bug_id in "${bug_ids[@]}"
do
    export JAVA_HOME=/opt/JDK/jdk1.7.0_80
    export PATH=$JAVA_HOME/bin:$PATH
    export JAVA_OPTS="-Xms4096m -Xmx4096m"
    GZoltar ${bug_id} ${pre_PID} ${pre_PID2}
    echo "GZoltar針對專案：'${pre_PID}'_'${bug_id}'，使用的公式為：'${sfll}'，已完成"
done

```

:::

### 額外補充

補充: GZoltar的公式檔案位置存放在
"gzoltar/com.gzoltar.fl/src/main/java/com/gzoltar/sfl/formulas"

再補充: 如果gzoltar錯誤時需要還原defects4J，可以使用以下腳本。
這是要將d4j的gzoltar的部分刪除。
```
touch init_d4j.sh
```
:::spoiler init_d4j.sh
```
#!/bin/bash
# 此檔案為還原GZoltar所產生的檔案。
# ------------------
# 檔案位置
# 此處需要自行修正。
D4J_DIR=~/d4j_project/

pre_PID=chart
pre_PID2=Chart

Num=26
# ------------------


for bug_id in $(seq 1 ${Num})
do
    # cd ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy
    rm -rf ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/sfl
    rm -f ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/gzoltar.ser
    rm -f ${D4J_DIR}${pre_PID}/${pre_PID}_${bug_id}_buggy/listTestMethods.txt
done
```
:::
```
chmod +x ./init_d4j.sh
```
