diff --git a/tests/convert/basic/task.json b/tests/convert/basic/task.json
new file mode 100644
index 0000000..4ffc375
--- /dev/null
+++ b/tests/convert/basic/task.json
@@ -0,0 +1,1328 @@
+{
+    "name": "h4 ex1",
+    "logPath": "h4-ex1.log",
+    "expireUnixTimestamp": 1728748740,
+    "stage": {
+        "sandboxExecServer": "172.17.0.1:5051",
+        "sandboxToken": "test",
+        "outputPath": "/tmp/joj3_result.json",
+        "stages": [
+            {
+                "name": "healthcheck",
+                "group": "",
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "/<function",
+                                "get_temp_directory",
+                                "at",
+                                "0x7fc3921ab1a0>/repo-health-checker",
+                                "-root=.",
+                                "-repoSize=50.5",
+                                "-meta=main.py",
+                                "-meta=README.md",
+                                "-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,1965adff52af61da8b9e089ff580d60f7e4c294a2930b9809c5cbdf76528de4d,c8bd62bf5297bac738b3845612fd595d677884093070904375463ab7953fce28",
+                                "-checkFileNameList=.gitignore,.gitattributes,push.yaml,release.yaml"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4096,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4096,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 4000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 8000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {
+                                "//tmp/repo-checker-u3awlhwg/repo-health-checker": {
+                                    "src": "//tmp/repo-checker-mc0n0t1l/repo-health-checker",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                }
+                            },
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "healthcheck",
+                        "with": {
+                            "score": 0,
+                            "comment": ""
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "Compilation",
+                "group": null,
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "make.sh"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 128000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 180000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 360000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {
+                                "tools/make.sh": {
+                                    "src": "/home/tt/.config/joj/tools/make.sh",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "src/main.c": {
+                                    "src": "/home/tt/.config/joj/src/main.c",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "src/task.h": {
+                                    "src": "/home/tt/.config/joj/src/task.h",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "srcCMakelist.txt": {
+                                    "src": "/home/tt/.config/joj/srcCMakelist.txt",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                }
+                            },
+                            "copyInCached": {
+                                "tools/make.sh": "tools/make.sh",
+                                "src/main.c": "src/main.c",
+                                "src/task.h": "src/task.h",
+                                "srcCMakelist.txt": "srcCMakelist.txt"
+                            },
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [
+                                "driver",
+                                "p2",
+                                "p2-msan"
+                            ],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stderr"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": false,
+                            "showMemory": false
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-status",
+                        "with": {
+                            "comment": "Congratulations! Your code compiled successfully."
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "File length check",
+                "group": null,
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "./file-length",
+                                "500",
+                                "400",
+                                "*.c",
+                                "*.h"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 4000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 8000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {
+                                "tools/file-length": {
+                                    "src": "/home/tt/.config/joj/tools/file-length",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                }
+                            },
+                            "copyInCached": {
+                                "tools/file-length": "tools/file-length"
+                            },
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "keyword",
+                        "with": {
+                            "match": [
+                                {
+                                    "keyword": [
+                                        "max"
+                                    ],
+                                    "score": 50
+                                },
+                                {
+                                    "keyword": [
+                                        "recommend"
+                                    ],
+                                    "score": 20
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": ""
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stderr"
+                            ],
+                            "showExitStatus": false,
+                            "showRuntime": false,
+                            "showMemory": false
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "Clang-tidy checks",
+                "group": null,
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "run-clang-tidy-18",
+                                "-header-filter=.*",
+                                "-quiet",
+                                "-load=/usr/local/lib/libcodequality.so",
+                                "-p",
+                                "build"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 65000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 4000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 8000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {},
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "clangtidy",
+                        "with": {
+                            "match": [
+                                {
+                                    "keyword": [
+                                        "codequality-no-global-variables"
+                                    ],
+                                    "score": 10
+                                },
+                                {
+                                    "keyword": [
+                                        "codequality-no-header-guard"
+                                    ],
+                                    "score": 10
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-function-size"
+                                    ],
+                                    "score": 50
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-duplicate-include"
+                                    ],
+                                    "score": 10
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-identifier-naming"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-redundant"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-misleading-indentation"
+                                    ],
+                                    "score": 10
+                                },
+                                {
+                                    "keyword": [
+                                        "readability-misplaced-array-index"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "cppcoreguidelines-init-variables"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "bugprone-suspicious-string-compare"
+                                    ],
+                                    "score": 8
+                                },
+                                {
+                                    "keyword": [
+                                        "google-global-names-in-headers"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "clang-diagnostic"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "clang-analyzer"
+                                    ],
+                                    "score": 5
+                                },
+                                {
+                                    "keyword": [
+                                        "misc performance"
+                                    ],
+                                    "score": 5
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stdout"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": false,
+                            "showMemory": false
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "Cppcheck check",
+                "group": null,
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "cppcheck",
+                                "--template='{\"file\":\"{file}\",\"line\":{line},",
+                                "\"column\":{column},",
+                                "\"severity\":\"{severity}\",",
+                                "\"message\":\"{message}\",",
+                                "\"id\":\"{id}\"}'",
+                                "--force",
+                                "--enable=all",
+                                "--quiet",
+                                "./"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 65000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 4000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 8000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {},
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "cppcheck",
+                        "with": {
+                            "match": [
+                                {
+                                    "keyword": [
+                                        "error"
+                                    ],
+                                    "score": 20
+                                },
+                                {
+                                    "keyword": [
+                                        "warning"
+                                    ],
+                                    "score": 10
+                                },
+                                {
+                                    "keyword": [
+                                        "portability"
+                                    ],
+                                    "score": 15
+                                },
+                                {
+                                    "keyword": [
+                                        "performance"
+                                    ],
+                                    "score": 15
+                                },
+                                {
+                                    "keyword": [
+                                        "style"
+                                    ],
+                                    "score": 10
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stderr"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": false,
+                            "showMemory": false
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "Cpplint check",
+                "group": null,
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "cpplint",
+                                "--linelength=120",
+                                "--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard",
+                                "--recursive",
+                                "--exclude=build",
+                                "."
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 65000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 4000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 8000000000,
+                            "memoryLimit": 4194304,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {},
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": []
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "cpplint",
+                        "with": {
+                            "comment": ""
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stdout"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": false,
+                            "showMemory": false
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "judge-base",
+                "group": "joj",
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "./driver",
+                                "./mumsh"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 3000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 6000000000,
+                            "memoryLimit": 78643200,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {},
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": [
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-base/case4.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 30000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 60000000000,
+                                "memoryLimit": 10485760,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            },
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-base/case5.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 4000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 8000000000,
+                                "memoryLimit": 4194304,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            },
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-base/case8.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 4000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 8000000000,
+                                "memoryLimit": 4194304,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            }
+                        ]
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "diff",
+                        "with": {
+                            "name": "diff",
+                            "cases": [
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-base/case4.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": false,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                },
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-base/case5.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": false,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                },
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-base/case8.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": false,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stderr"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": true,
+                            "showMemory": true
+                        }
+                    }
+                ]
+            },
+            {
+                "name": "judge-msan",
+                "group": "joj",
+                "executor": {
+                    "name": "sandbox",
+                    "with": {
+                        "default": {
+                            "args": [
+                                "./driver",
+                                "./mumsh-msan"
+                            ],
+                            "env": [
+                                "PATH=/usr/bin:/bin:/usr/local/bin"
+                            ],
+                            "stdin": {
+                                "src": null,
+                                "content": "",
+                                "fileId": null,
+                                "name": null,
+                                "max": 4194304,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stdout": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stdout",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "stderr": {
+                                "src": null,
+                                "content": null,
+                                "fileId": null,
+                                "name": "stderr",
+                                "max": 4000000000,
+                                "symlink": null,
+                                "streamIn": false,
+                                "streamOut": false,
+                                "pipe": false
+                            },
+                            "cpuLimit": 10000000000,
+                            "realCpuLimit": 0,
+                            "clockLimit": 20000000000,
+                            "memoryLimit": 524288000,
+                            "stackLimit": 0,
+                            "procLimit": 50,
+                            "cpuRateLimit": 0,
+                            "cpuSetLimit": "",
+                            "copyIn": {},
+                            "copyInCached": {},
+                            "copyInDir": ".",
+                            "copyOut": [],
+                            "copyOutCached": [],
+                            "copyOutMax": 0,
+                            "copyOutDir": "",
+                            "tty": false,
+                            "strictMemoryLimit": false,
+                            "dataSegmentLimit": false,
+                            "addressSpaceLimit": false
+                        },
+                        "cases": [
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-msan/case4.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 30000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 60000000000,
+                                "memoryLimit": 10485760,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            },
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-msan/case5.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 4000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 8000000000,
+                                "memoryLimit": 4194304,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            },
+                            {
+                                "args": null,
+                                "env": [
+                                    "PATH=/usr/bin:/bin:/usr/local/bin"
+                                ],
+                                "stdin": {
+                                    "src": "/home/tt/.config/joj/judge-msan/case6.in",
+                                    "content": null,
+                                    "fileId": null,
+                                    "name": null,
+                                    "max": 4194304,
+                                    "symlink": null,
+                                    "streamIn": false,
+                                    "streamOut": false,
+                                    "pipe": false
+                                },
+                                "stdout": null,
+                                "stderr": null,
+                                "cpuLimit": 4000000000,
+                                "realCpuLimit": null,
+                                "clockLimit": 8000000000,
+                                "memoryLimit": 4194304,
+                                "stackLimit": null,
+                                "procLimit": 50,
+                                "cpuRateLimit": null,
+                                "cpuSetLimit": null,
+                                "copyIn": null,
+                                "copyInCached": null,
+                                "copyInDir": null,
+                                "copyOut": null,
+                                "copyOutCached": null,
+                                "copyOutMax": null,
+                                "copyOutDir": null,
+                                "tty": null,
+                                "strictMemoryLimit": null,
+                                "dataSegmentLimit": null,
+                                "addressSpaceLimit": null
+                            }
+                        ]
+                    }
+                },
+                "parsers": [
+                    {
+                        "name": "diff",
+                        "with": {
+                            "name": "diff",
+                            "cases": [
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-msan/case4.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": false,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                },
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-msan/case5.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": false,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                },
+                                {
+                                    "outputs": [
+                                        {
+                                            "score": 0,
+                                            "fileName": "stdout",
+                                            "answerPath": "/home/tt/.config/joj/judge-msan/case6.out",
+                                            "forceQuitOnDiff": true,
+                                            "alwaysHide": true,
+                                            "compareSpace": true
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "dummy",
+                        "with": {
+                            "comment": "\n\n### Details\n"
+                        }
+                    },
+                    {
+                        "name": "result-detail",
+                        "with": {
+                            "score": 0,
+                            "comment": "",
+                            "showFiles": [
+                                "stderr"
+                            ],
+                            "showExitStatus": true,
+                            "showRuntime": true,
+                            "showMemory": true
+                        }
+                    }
+                ]
+            }
+        ]
+    },
+    "teapot": {
+        "logPath": "h4-ex1-joint-teapot-debug.log",
+        "scoreboardPath": "h4-ex1-scoreboard.csv",
+        "failedTablePath": "h4-ex1-failed-table.md",
+        "gradingRepoName": "Nuvole-joj",
+        "skipIssue": false,
+        "skipScoreboard": false,
+        "skipFailedTable": false
+    }
+}
diff --git a/tests/immutable_file/.gitattributes b/tests/immutable_file/.gitattributes
new file mode 100644
index 0000000..b910c4a
--- /dev/null
+++ b/tests/immutable_file/.gitattributes
@@ -0,0 +1,33 @@
+*.avi filter=lfs diff=lfs merge=lfs -text
+*.bz2 filter=lfs diff=lfs merge=lfs -text
+*.djvu filter=lfs diff=lfs merge=lfs -text
+*.doc filter=lfs diff=lfs merge=lfs -text
+*.docx filter=lfs diff=lfs merge=lfs -text
+*.epub filter=lfs diff=lfs merge=lfs -text
+*.gz filter=lfs diff=lfs merge=lfs -text
+*.ipynb filter=lfs diff=lfs merge=lfs -text
+*.jpeg filter=lfs diff=lfs merge=lfs -text
+*.JPEG filter=lfs diff=lfs merge=lfs -text
+*.jpg filter=lfs diff=lfs merge=lfs -text
+*.JPG filter=lfs diff=lfs merge=lfs -text
+*.mkv filter=lfs diff=lfs merge=lfs -text
+*.mp4 filter=lfs diff=lfs merge=lfs -text
+*.ods filter=lfs diff=lfs merge=lfs -text
+*.odt filter=lfs diff=lfs merge=lfs -text
+*.otf filter=lfs diff=lfs merge=lfs -text
+*.pdf filter=lfs diff=lfs merge=lfs -text
+*.PDF filter=lfs diff=lfs merge=lfs -text
+*.png filter=lfs diff=lfs merge=lfs -text
+*.PNG filter=lfs diff=lfs merge=lfs -text
+*.ppt filter=lfs diff=lfs merge=lfs -text
+*.pptx filter=lfs diff=lfs merge=lfs -text
+*.ps filter=lfs diff=lfs merge=lfs -text
+*.rar filter=lfs diff=lfs merge=lfs -text
+*.tar filter=lfs diff=lfs merge=lfs -text
+*.tgz filter=lfs diff=lfs merge=lfs -text
+*.ttf filter=lfs diff=lfs merge=lfs -text
+*.webm filter=lfs diff=lfs merge=lfs -text
+*.xls filter=lfs diff=lfs merge=lfs -text
+*.xlsx filter=lfs diff=lfs merge=lfs -text
+*.xz filter=lfs diff=lfs merge=lfs -text
+*.zip filter=lfs diff=lfs merge=lfs -text
diff --git a/tests/immutable_file/.gitignore b/tests/immutable_file/.gitignore
new file mode 100644
index 0000000..754f776
--- /dev/null
+++ b/tests/immutable_file/.gitignore
@@ -0,0 +1,23 @@
+################################
+## White list based gitignore ##
+################################
+
+# forbidden
+*
+.*
+
+# allowed
+!.gitignore
+!.gitattributes
+!.gitea/
+!.gitea/issue_template/
+!.gitea/workflows/
+!*.yaml
+!Makefile
+!CMakeLists.txt
+!h[0-8]/
+!*.m
+!*.c
+!*.cpp
+!*.h
+!*.md
diff --git a/tests/immutable_file/push.yaml b/tests/immutable_file/push.yaml
new file mode 100644
index 0000000..2f890b6
--- /dev/null
+++ b/tests/immutable_file/push.yaml
@@ -0,0 +1,18 @@
+name: Run JOJ3 on Push
+on: [push]
+jobs:
+  run:
+    container:
+      image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim
+      volumes:
+        - /home/tt/.config:/home/tt/.config
+        - /home/tt/.cache:/home/tt/.cache
+        - /home/tt/.ssh:/home/tt/.ssh
+    steps:
+      - name: Check out repository code
+        uses: https://gitea.com/BoYanZh/checkout@focs
+        with:
+          fetch-depth: 0
+      - name: run joj3
+        run: |
+          sudo -E -u tt joj3 -conf-root /home/tt/.config/joj
diff --git a/tests/immutable_file/release.yaml b/tests/immutable_file/release.yaml
new file mode 100644
index 0000000..afd2838
--- /dev/null
+++ b/tests/immutable_file/release.yaml
@@ -0,0 +1,20 @@
+name: Run JOJ3 on Release
+on:
+  release:
+    types: [published]
+jobs:
+  run:
+    container:
+      image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim
+      volumes:
+        - /home/tt/.config:/home/tt/.config
+        - /home/tt/.cache:/home/tt/.cache
+        - /home/tt/.ssh:/home/tt/.ssh
+    steps:
+      - name: Check out repository code
+        uses: https://gitea.com/BoYanZh/checkout@focs
+        with:
+          fetch-depth: 0
+      - name: run joj3
+        run: |
+          sudo -E -u tt joj3 -conf-root /home/tt/.config/joj -msg "feat(h1-release): joj on ${{ github.ref }}"