Add dotnet-launcher test case - Script
authorj-h.choi <j-h.choi@samsung.com>
Tue, 1 Dec 2020 07:40:12 +0000 (16:40 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Wed, 23 Dec 2020 23:52:31 +0000 (08:52 +0900)
Change-Id: Ief02095307e51f8237c34e818bc7697cdecf5319

17 files changed:
tests/TCs/1_AOT/AOT.py [new file with mode: 0755]
tests/TCs/1_AOT/README.md [new file with mode: 0644]
tests/TCs/2_PLUGIN/PLUGIN.py [new file with mode: 0755]
tests/TCs/2_PLUGIN/README.md [new file with mode: 0644]
tests/TCs/3_PRELOAD/PRELOAD.py [new file with mode: 0755]
tests/TCs/3_PRELOAD/README.md [new file with mode: 0644]
tests/TCs/4_TAC/README.md [new file with mode: 0644]
tests/TCs/4_TAC/TAC.py [new file with mode: 0755]
tests/TCs/5_TLC/README.md [new file with mode: 0644]
tests/TCs/5_TLC/TLC.py [new file with mode: 0755]
tests/TCs/6_TOOL/README.md [new file with mode: 0644]
tests/TCs/6_TOOL/TOOL.py [new file with mode: 0755]
tests/TCs/7_LAUNCH/LAUNCH.py [new file with mode: 0755]
tests/TCs/7_LAUNCH/README.md [new file with mode: 0644]
tests/TCs/ALL.py [new file with mode: 0755]
tests/TCs/README.md [new file with mode: 0644]
tests/TCs/Utils.py [new file with mode: 0755]

diff --git a/tests/TCs/1_AOT/AOT.py b/tests/TCs/1_AOT/AOT.py
new file mode 100755 (executable)
index 0000000..f44efd5
--- /dev/null
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from pathlib import Path
+from Utils import *
+
+
+module_name = "AOT"
+
+# The `Launcher_TC_AOT_01` application does not generate native image.
+def TC_01():
+    if "OK" not in create_spc_ni():
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    sln_name = "Launcher_TC_AOT_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_AOT_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" in raw:
+        return "FAIL : The .native_image folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The .ni.dll files should not exist"
+
+    return "PASS"
+
+# The `Launcher_TC_AOT_02` application generates native image.
+def TC_02():
+    if "OK" not in create_spc_ni():
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    sln_name = "Launcher_TC_AOT_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_AOT_02.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" not in raw:
+        return "FAIL : The .native_image folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.native_image/ -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match in the application"
+
+    for ni in lines1:
+        is_same = False
+        for dll in lines2:
+            if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                is_same = True
+                break
+        if not is_same:
+            return "FAIL : The file name of .dll and .ni.dll must match in the application"
+
+    return "PASS"
+
+# The `Launcher_TC_AOT_03` application does not generate native image.
+def TC_03():
+    if "OK" not in remove_system_ni():
+        return "FAIL : Remove the platform native image"
+
+    sln_name = "Launcher_TC_AOT_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_AOT_03.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" in raw:
+        return "FAIL : The .native_image folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The .ni.dll files should not exist"
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_AOT_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_AOT_02.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_AOT_03.Tizen")
+
+    create_spc_ni()
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03,
+'AOT_TC_01': TC_01, 'AOT_TC_02': TC_02, 'AOT_TC_03': TC_03
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/1_AOT/README.md b/tests/TCs/1_AOT/README.md
new file mode 100644 (file)
index 0000000..e5bc7b3
--- /dev/null
@@ -0,0 +1,69 @@
+# Test Case for dotnet-launcher - AOT
+
+This script(AOT.py) is a test that verifies the behavior of **prefer_dotnet_aot** metadata.
+```
+<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="false" />
+```
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **AOT** test
+```
+launcher/tests/TCs$ ./1_AOT/AOT.py
+launcher/tests/TCs/1_AOT$ ./AOT.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/1_AOT$ ./AOT.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : The Launcher_TC_AOT_01 application does not generate native image.
+```
+  1. The `System.Private.CoreLib.ni.dll`(SPC.dll.Backup) file exists.
+  2. There is no `prefer_dotnet_aot` metadata in the manifest.
+  3. The `.native_image` folder and `.ni.dll` files do not exist.
+* TC_02
+```
+  PASS : The Launcher_TC_AOT_02 application generates native image.
+```
+  1. The `System.Private.CoreLib.ni.dll`(SPC.dll.Backup) file exists.
+  2. The `prefer_dotnet_aot` metadata value is `true` in the manifest.
+  3. The `.native_image` folder and `.ni.dll` files exist.
+  4. The number of `.dll` and `.ni.dll` in the application is the same.
+  5. The file name of `.dll` and `.ni.dll` must match in the application
+* TC_03
+```
+  PASS : The Launcher_TC_AOT_03 application does not generate native image.
+```
+  1. The `System.Private.CoreLib.ni.dll`(SPC.dll.Backup) file does not exist.
+  2. The `prefer_dotnet_aot` metadata value is `true` in the manifest.
+  3. The `.native_image` folder and `.ni.dll` files do not exist.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/2_PLUGIN/PLUGIN.py b/tests/TCs/2_PLUGIN/PLUGIN.py
new file mode 100755 (executable)
index 0000000..f48e37b
--- /dev/null
@@ -0,0 +1,326 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "PLUGIN"
+
+# The `Launcher_TC_PLUGIN_01` application should not have a library of other OS.
+def TC_01():
+    sln_name = "Launcher_TC_PLUGIN_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls {root_path}/bin/")
+    if ("libHarfBuzzSharp.dylib" in raw) or ("libHarfBuzzSharp.dll" in raw):
+        return "FAIL : Library of other OS should not exist"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_02` application must have a library of Tizen OS.
+def TC_02():
+    sln_name = "Launcher_TC_PLUGIN_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_02.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if f"{root_path}/bin/libSkiaSharp.so" not in raw:
+        return "FAIL : The libSkiaSharp.so library should exist"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_03` application does not generate native image.
+def TC_03():
+    if "OK" not in create_spc_ni():
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    sln_name = "Launcher_TC_PLUGIN_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_03.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" in raw:
+        return "FAIL : The .native_image folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The .ni.dll files should not exist"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_04` application generates native image.
+def TC_04():
+    if "OK" not in create_spc_ni():
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    sln_name = "Launcher_TC_PLUGIN_04.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_04.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" not in raw:
+        return "FAIL : The .native_image folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.native_image/ -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match in the application"
+
+    for ni in lines1:
+        is_same = False
+        for dll in lines2:
+            if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                is_same = True
+                break
+        if not is_same:
+            return "FAIL : The file name of .dll and .ni.dll must match in the application"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_05` application must not have TAC applied.
+def TC_05():
+    sln_name = "Launcher_TC_PLUGIN_05.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_05.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" in raw:
+        return "FAIL : The .tac_symlink folder should not exist"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_06` application must have TAC applied.
+def TC_06():
+    sln_name = "Launcher_TC_PLUGIN_06.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_06.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.6.0.967/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_07` application must not have TLC applied.
+def TC_07():
+    sln_name = "Launcher_TC_PLUGIN_07.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_07.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if f"{root_path}/bin/libSkiaSharp.so" not in raw:
+        return "FAIL : The libSkiaSharp.so library should exist only"
+    if "->" in raw:
+        return "FAIL : The libSkiaSharp.so library should not be a symbolic link"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    return "PASS"
+
+# The `Launcher_TC_PLUGIN_08` application must have TLC applied.
+def TC_08():
+    sln_name = "Launcher_TC_PLUGIN_08.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_08.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_02.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_03.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_04.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_05.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_06.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_07.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_08.Tizen")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05, 'TC_06': TC_06, 'TC_07': TC_07, 'TC_08': TC_08,
+'PLUGIN_TC_01': TC_01, 'PLUGIN_TC_02': TC_02, 'PLUGIN_TC_03': TC_03, 'PLUGIN_TC_04': TC_04,
+'PLUGIN_TC_05': TC_05, 'PLUGIN_TC_06': TC_06, 'PLUGIN_TC_07': TC_07, 'PLUGIN_TC_08': TC_08
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/2_PLUGIN/README.md b/tests/TCs/2_PLUGIN/README.md
new file mode 100644 (file)
index 0000000..29def58
--- /dev/null
@@ -0,0 +1,107 @@
+# Test Case for dotnet-launcher - INSTALLER-PLUGIN
+
+This script(PLUGIN.py) is a test that verifies the behavior of **install plugin**.
+check the delete_unused_library_plugin, prefer_dotnet_aot_plugin and prefer_nuget_cache_plugin.
+```
+<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+<metadata key="http://tizen.org/metadata/prefer_nuget_cache" value="true" />
+```
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **INSTALLER-PLUGIN** test
+```
+launcher/tests/TCs$ ./2_PLUGIN/PLUGIN.py
+launcher/tests/TCs/2_PLUGIN$ ./PLUGIN.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/2_PLUGIN$ ./PLUGIN.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : The Launcher_TC_PLUGIN_01 application should not have a library of other OS.
+```
+  1. Nuget without `Tizen(tizen-armel, tizen-x86, ...)` related library is used.
+  2. The library does not exist in the application.
+* TC_02
+```
+  PASS : The Launcher_TC_PLUGIN_02 application must have a library of Tizen OS.
+```
+  1. Nuget with `Tizen(tizen-armel, tizen-x86, ...)` related library is used.
+  2. The library exists in the application.
+* TC_03
+```
+  PASS : The Launcher_TC_PLUGIN_03 application does not generate native image.
+```
+  1. The `System.Private.CoreLib.ni.dll`(SPC.dll.Backup) file exists.
+  2. The `prefer_dotnet_aot` metadata value is `false` in the manifest.
+  3. The `.native_image` folder and `.ni.dll` files do not exist.
+* TC_04
+```
+  PASS : The Launcher_TC_PLUGIN_04 application generates native image.
+```
+  1. The `System.Private.CoreLib.ni.dll`(SPC.dll.Backup) file exists.
+  2. The `prefer_dotnet_aot` metadata value is `true` in the manifest.
+  3. The `.native_image` folder and `.ni.dll` files exist.
+  4. The number of `.dll` and `.ni.dll` in the application is the same.
+  5. The file name of `.dll` and `.ni.dll` must match in the application
+* TC_05
+```
+  PASS : The Launcher_TC_PLUGIN_05 application must not have TAC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `false` in the manifest.
+  2. The `.tac_symlink` folder should not exist.
+* TC_06
+```
+  PASS : The Launcher_TC_PLUGIN_06 application must have TAC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The `.tac_symlink` folder and `symbolic link` files exist.
+  3. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  4. The original file of the `symbolic link` must exist in the `TAC`.
+* TC_07
+```
+  PASS : The Launcher_TC_PLUGIN_07 application must not have TLC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `false` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. The `library(.so)` should exist only in the application.
+  4. The `library(.so)` should not be a symbolic link.
+  5. The arch of the target and the arch of the library must match.
+* TC_08
+```
+  PASS : The Launcher_TC_PLUGIN_08 application must have TLC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  4. The `library(.so)` should be a symbolic link.
+  5. The arch of the target and the arch of the library must match.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/3_PRELOAD/PRELOAD.py b/tests/TCs/3_PRELOAD/PRELOAD.py
new file mode 100755 (executable)
index 0000000..0b5c781
--- /dev/null
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "PRELOAD"
+
+# All the `.dlls` in the .preload file must be loaded in the memory.
+def TC_01():
+    sln_name = "Launcher_TC_PRELOAD_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PRELOAD_01.Tizen"
+
+    raw = prepare_candidate_process(f"dotnet-loader", f"{pkg_id}")
+    if "OK" not in raw:
+        return f"FAIL : Candidate process should have dotnet-loader"
+
+    pid = raw.split(":")[1].strip()
+
+    raw = cmd(f"shell find {PRELOAD_DIR} -name *.preload")
+    lines = [l for l in raw.splitlines() if "NUI" not in l]
+    if len(lines) == 0:
+        return "FAIL : The .preload file should exist"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep {FRAMEWORK_DIR}")
+    if len([l for l in raw.splitlines()]) == 0:
+        return "FAIL : The assembly of .preload file should be loaded in the candidate process"
+
+    if (f"{FRAMEWORK_DIR}Tizen.Runtime." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen." not in raw) or \
+       (f"{FRAMEWORK_DIR}ElmSharp." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Applications.Common." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Applications.UI." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Log." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.System.Information." not in raw) or \
+       (f"{FRAMEWORK_DIR}XSF." not in raw):
+        return "FAIL : The assembly of .preload file should be loaded in the candidate process"
+
+    return "PASS"
+
+# All the `.dlls` in the .preload file must be loaded in the memory.
+def TC_02():
+    sln_name = "Launcher_TC_PRELOAD_02"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PRELOAD_02"
+
+    raw = prepare_candidate_process(f"dotnet-nui-loader", f"{pkg_id}")
+    if "OK" not in raw:
+        return f"FAIL : Candidate process should have dotnet-nui-loader"
+
+    pid = raw.split(":")[1].strip()
+
+    raw = cmd(f"shell find {PRELOAD_DIR} -name *.preload")
+    lines = [l for l in raw.splitlines() if "XSF" not in l and "ElmSharp" not in l]
+    if len(lines) == 0:
+        return "FAIL : The .preload file should exist"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep {FRAMEWORK_DIR}")
+    if len([l for l in raw.splitlines()]) == 0:
+        return "FAIL : The assembly of .preload file should be loaded in the candidate process"
+
+    if (f"{FRAMEWORK_DIR}Tizen.Runtime." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Applications.Common." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Applications.UI." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.Log." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.NUI." not in raw) or \
+       (f"{FRAMEWORK_DIR}Tizen.System.Information." not in raw):
+        return "FAIL : The assembly of .preload file should be loaded in the candidate process"
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PRELOAD_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PRELOAD_02")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02,
+'PRELOAD_TC_01': TC_01, 'PRELOAD_TC_02': TC_02
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/3_PRELOAD/README.md b/tests/TCs/3_PRELOAD/README.md
new file mode 100644 (file)
index 0000000..7070af0
--- /dev/null
@@ -0,0 +1,58 @@
+# Test Case for dotnet-launcher - PRELOAD
+
+This script(PRELOAD.py) is a test that verifies the behavior of **preload**.
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **PRELOAD** test
+```
+launcher/tests/TCs$ ./3_PRELOAD/PRELOAD.py
+launcher/tests/TCs/3_PRELOAD$ ./PRELOAD.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/3_PRELOAD$ ./PRELOAD.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : All the .dlls in the .preload file must be loaded in the memory.
+```
+  1. The `.preload` file should exist.
+  2. Candidate process should have `dotnet-loader`.
+  3. Get the pid value.
+  4. The assembly of `.preload` file should be loaded in the candidate process.
+* TC_02
+```
+  PASS : All the .dlls in the .preload file must be loaded in the memory.
+```
+  1. The `.preload` file should exist.
+  2. Candidate process should have `dotnet-nui-loader`.
+  3. Get the pid value.
+  4. The assembly of `.preload` file should be loaded in the candidate process.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/4_TAC/README.md b/tests/TCs/4_TAC/README.md
new file mode 100644 (file)
index 0000000..99e2409
--- /dev/null
@@ -0,0 +1,134 @@
+# Test Case for dotnet-launcher - TAC
+
+This script(TAC.py) is a test that verifies the behavior of **prefer_nuget_cache** metadata.
+Verifies that the **assembly(.dll)** can be shared.
+```
+<metadata key="http://tizen.org/metadata/prefer_nuget_cache" value="true" />
+<metadata key="http://tizen.org/metadata/prefer_nuget_cache" value="false" />
+```
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **TAC** test
+```
+launcher/tests/TCs$ ./4_TAC/TAC.py
+launcher/tests/TCs/4_TAC$ ./TAC.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/4_TAC$ ./TAC.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : The Launcher_TC_TAC_01 application must have TAC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The `.tac_symlink` folder and `symbolic link` files exist.
+  3. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  4. The original file of the `symbolic link` must exist in the `TAC`.
+  5. The nuget in the `TAC` should be loaded when running the application.
+* TC_02
+```
+  PASS : The Launcher_TC_TAC_02 application must have TAC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. Install the application with the `same package ID`.
+  3. The `.tac_symlink` folder and `symbolic link` files exist.
+  4. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  5. The original file of the `symbolic link` must exist in the `TAC`.
+  6. The nuget in the `TAC` should be loaded when running the application.
+* TC_03
+```
+  PASS : The Launcher_TC_TAC_03 application is normally TAC applied when updating.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. Update the application with the `same package ID`.
+  3. The `.tac_symlink` folder and `symbolic link` files exist.
+  4. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  5. The original file of the `symbolic link` must exist in the `TAC`.
+  6. Changes to the nuget should be applied normally.
+  7. The nuget in the `TAC` should be loaded when running the application.
+* TC_04
+```
+  PASS : The Launcher_TC_TAC_04 application should not apply TAC when updating.
+```
+  1. There is no `prefer_nuget_cache` metadata in the manifest.
+  2. Update the application with the `same package ID`.
+  3. The `.tac_symlink` folder should not exist.
+  4. The nugets prior to updating the application should not exist in the `TAC`.
+  5. The nuget in the `application` should be loaded when running the application.
+* TC_05
+```
+  PASS : The Launcher_TC_TAC_05, Launcher_TC_TAC_06 applications using the same nuget are normally TAC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. Install two different applications using the `same nuget`.
+  3. Both applications have a `.tac_symlink` folder and a `symbolic link` file.
+  4. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  5. The original file of the `symbolic link` must exist in the `TAC`.
+  6. Uninstall one application.
+  7. All previous nugets must exist.
+  8. The nuget in the `TAC` should be loaded when running the application.
+* TC_06
+```
+  PASS : The Launcher_TC_TAC_07 application is normally TAC applied when uninstall.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. Install the application.
+  3. The `.tac_symlink` folder and `symbolic link` files exist.
+  4. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  5. The original file of the `symbolic link` must exist in the `TAC`.
+  6. Uninstall the application.
+  7. The nuget should not exist in the `TAC`.
+* TC_07
+```
+  PASS : The Launcher_TC_TAC_08 application should be applied to TAC, but The Launcher_TC_TAC_09 application should not be applied to TAC.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. Install two different applications.
+  3. The two applications use the `same version` of nuget, but the `SHA value` is different.
+  4. The first installed application has a `.tac_symlink` folder and `symbolic link` files.
+  5. The number of `.dll` in the `.tac_symlink` folder and `.dll` in the `TAC` must match.
+  6. The original file of the `symbolic link` must exist in the `TAC`.
+  7. The second installed application does not have a `.tac_symlink` folder.
+  8. The nuget in the `application` should be loaded when running the second application.
+* TC_08
+```
+  PASS : The Launcher_TC_TAC_10 application should match the information of nuget with the value of TAC database.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The `.tac_symlink` folder and `symbolic link` files exist.
+  3. The information in `nuget` must match the `TAC database` value.
+* TC_09
+```
+  PASS : The Launcher_TC_TAC_11 application must match the version of the nuget in .deps.json and the version of the nuget in TAC DB.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget version of .deps.json and the nuget version of TAC database must match.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/4_TAC/TAC.py b/tests/TCs/4_TAC/TAC.py
new file mode 100755 (executable)
index 0000000..7b60030
--- /dev/null
@@ -0,0 +1,595 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "TAC"
+
+# The `Launcher_TC_TAC_01` application must have TAC applied.
+def TC_01():
+    sln_name = "Launcher_TC_TAC_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.6.0.967/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{DOTNET_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Platform.Tizen.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Core.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_02` application must have TAC applied.
+def TC_02():
+    sln_name = "Launcher_TC_TAC_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Newtonsoft.Json/12.0.1/ -name *.dll -not -name *.ni.dll")
+    lines3 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2)+len(lines3):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Platform.Tizen.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Core.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Newtonsoft.Json.dll")
+    if f"{DOTNET_DIR}Newtonsoft.Json/12.0.1/Newtonsoft.Json.dll" not in raw:
+        return "FAIL : The Newtonsoft.Json in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_03` application is normally TAC applied when updating.
+def TC_03():
+    sln_name = "Launcher_TC_TAC_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.8.0.1687/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}sqlite-net-base/1.7.335/ -name *.dll -not -name *.ni.dll")
+    lines3 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}SQLitePCLRaw.core/2.0.3/ -name *.dll -not -name *.ni.dll")
+    lines4 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2)+len(lines3)+len(lines4):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The Xamarin.Forms/4.8.0.1364 nuget should not exist in {DOTNET_DIR}"
+    
+    raw = cmd(f"shell find {DOTNET_DIR}Newtonsoft.Json/12.0.1/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The Newtonsoft.Json/12.0.1 nuget should not exist in {DOTNET_DIR}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Platform.Tizen.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Core.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep SQLite-net.dll")
+    if f"{DOTNET_DIR}sqlite-net-base/1.7.335/SQLite-net.dll" not in raw:
+        return "FAIL : The sqlite-net-base in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep SQLitePCLRaw.core.dll")
+    if f"{DOTNET_DIR}SQLitePCLRaw.core/2.0.3/SQLitePCLRaw.core.dll" not in raw:
+        return "FAIL : The SQLitePCLRaw.core in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_04` application should not apply TAC when updating.
+def TC_04():
+    sln_name = "Launcher_TC_TAC_04.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" in raw:
+        return "FAIL : The .tac_symlink folder should not exist"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The Xamarin.Forms/4.8.0.1364 nuget should not exist in {DOTNET_DIR}"
+    
+    raw = cmd(f"shell find {DOTNET_DIR}Newtonsoft.Json/12.0.1/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The Newtonsoft.Json/12.0.1 nuget should not exist in {DOTNET_DIR}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}sqlite-net-base/1.7.335/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The sqlite-net-base/1.7.335 nuget should not exist in {DOTNET_DIR}"
+    
+    raw = cmd(f"shell find {DOTNET_DIR}SQLitePCLRaw.core/2.0.3/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The SQLitePCLRaw.core/2.0.3 nuget should not exist in {DOTNET_DIR}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{root_path}/bin/Xamarin.Forms.Platform.Tizen.dll" not in raw) and \
+       (f"{root_path}/bin/Xamarin.Forms.Core.dll" not in raw) and \
+       (f"{root_path}/bin/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the application should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_05`, `Launcher_TC_TAC_06` applications using the same nuget are normally TAC applied.
+def TC_05():
+    sln_name = "Launcher_TC_TAC_05.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id1 = f"org.tizen.example.Launcher_TC_TAC_05.Tizen"
+
+    root_path = get_root_path(f"{pkg_id1}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id1}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    sln_name = "Launcher_TC_TAC_06.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id2 = f"org.tizen.example.Launcher_TC_TAC_06.Tizen"
+
+    root_path = get_root_path(f"{pkg_id2}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id2}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    raw = cmd(f"uninstall {pkg_id1}")
+    if "key[end] val[ok]" not in raw:
+        return f"FAIL : Uninstall the application for {pkg_id1}"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id2}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id2}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Platform.Tizen.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Core.dll" not in raw) and \
+       (f"{DOTNET_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id2}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_07` application is normally TAC applied when uninstall.
+def TC_06():
+    sln_name = "Launcher_TC_TAC_07.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_07.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.4.0.991864/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    raw = cmd(f"uninstall {pkg_id}")
+    if "key[end] val[ok]" not in raw:
+        return f"FAIL : Uninstall the application for {pkg_id}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.4.0.991864/ -name *.dll")
+    if "No such file or directory" not in raw:
+        return f"FAIL : The Xamarin.Forms/4.4.0.991864 nuget should not exist in {DOTNET_DIR}"
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_08` application should be applied to TAC, but The `Launcher_TC_TAC_09` application should not be applied to TAC.
+def TC_07():
+    raw = cmd(f"shell find {FRAMEWORK_DIR}/XSF.*")
+    if "XSF.dll" in raw:
+        cmd(f"shell mv {FRAMEWORK_DIR}/XSF.dll {FRAMEWORK_DIR}/XSF.dll2")
+    elif "XSF.ni.dll" in raw:
+        cmd(f"shell mv {FRAMEWORK_DIR}/XSF.ni.dll {FRAMEWORK_DIR}/XSF.ni.dll2")
+
+    sln_name = "Launcher_TC_TAC_08.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_08.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}XSF/1.0.0.0/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    sln_name = "Launcher_TC_TAC_09.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_09.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink -name XSF.dll -not -name XSF.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The version is the same Nuget, but the SHA value is different"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep XSF.dll")
+    if f"{root_path}/bin/XSF.dll" not in raw:
+        return "FAIL : The XSF in the application should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The Launcher_TC_TAC_10 application should match the information of nuget with the value of TAC DB.
+def TC_08():
+    sln_name = "Launcher_TC_TAC_10.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_10.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {DOTNET_DIR}.TAC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TAC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for rcd in lines:
+        if ("Xamarin.Forms/4.8.0.1560" not in rcd) and \
+           ("Google.Apis.Core/1.49.0" not in rcd) and \
+           ("Google.Apis/1.49.0" not in rcd) and \
+           ("Newtonsoft.Json/12.0.3" not in rcd):
+            return "FAIL : TAC database must have a valid value"
+
+    return "PASS"
+
+# The Launcher_TC_TAC_11 application must match the version of the nuget in .deps.json and the version of the nuget in TAC DB.
+def TC_09():
+    sln_name = "Launcher_TC_TAC_11.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_11.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {DOTNET_DIR}.TAC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TAC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for nuget in lines:
+        name = nuget.split("|")[3]
+        version = nuget.split("|")[4]
+        raw = cmd(f"shell cat {root_path}/{sln_name}.deps.json | grep {name}/")
+        if f"{version}" not in f"{raw}":
+            return "FAIL : "
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_00.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_06.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_07.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_08.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_09.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_10.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TAC_11.Tizen")
+
+    cmd(f"shell mv {FRAMEWORK_DIR}/XSF.dll2 {FRAMEWORK_DIR}/XSF.dll")
+    cmd(f"shell mv {FRAMEWORK_DIR}/XSF.ni.dll2 {FRAMEWORK_DIR}/XSF.ni.dll")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05, 'TC_06': TC_06, 'TC_07': TC_07, 'TC_08': TC_08, 'TC_09': TC_09,
+'TAC_TC_01': TC_01, 'TAC_TC_02': TC_02, 'TAC_TC_03': TC_03, 'TAC_TC_04': TC_04, 'TAC_TC_05': TC_05,
+'TAC_TC_06': TC_06, 'TAC_TC_07': TC_07, 'TAC_TC_08': TC_08, 'TAC_TC_09': TC_09
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/5_TLC/README.md b/tests/TCs/5_TLC/README.md
new file mode 100644 (file)
index 0000000..68f0448
--- /dev/null
@@ -0,0 +1,147 @@
+# Test Case for dotnet-launcher - TLC
+
+This script(TLC.py) is a test that verifies the behavior of **prefer_nuget_cache** metadata.
+Verifies that the **library(.so)** can be shared.
+```
+<metadata key="http://tizen.org/metadata/prefer_nuget_cache" value="true" />
+<metadata key="http://tizen.org/metadata/prefer_nuget_cache" value="false" />
+```
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **TLC** test
+```
+launcher/tests/TCs$ ./5_TLC/TLC.py
+launcher/tests/TCs/5_TLC$ ./TLC.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/5_TLC$ ./TLC.py TC_01
+```
+  *NOTE : The update test cannot be run individually. So, When you run the update test, it automatically performs all related tests([TC_02, TC_03], [TC_04, TC_05, TC_06]).*
+
+### Description
+* TC_01
+```
+  PASS : The Launcher_TC_TLC_01 application must have TLC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  4. The `library(.so)` should be a symbolic link.
+  5. The arch of the target and the arch of the library must match.
+  6. The library in the `TLC` should be loaded when running the application.
+* TC_02
+```
+  PASS : The Launcher_TC_TLC_02 application must have TLC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Install the application with the `same package ID`.
+  4. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  5. The `library(.so)` should be a symbolic link.
+  6. The arch of the target and the arch of the library must match.
+  7. The library in the `TLC` should be loaded when running the application.
+* TC_03
+```
+  PASS : The Launcher_TC_TLC_03 application should not apply TLC when updating.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used does not have a TFM folder related to Tizen.
+  3. Update the application with the `same package ID`.
+  4. The `library(.so)` should not exist in the application and TLC.
+  5. The library should not be loaded when running the application.
+* TC_04
+```
+  PASS : The Launcher_TC_TLC_04 application is normally TLC applied when updating.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Update the application with the `same package ID`.
+  4. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  5. The `library(.so)` should be a symbolic link.
+  6. The arch of the target and the arch of the library must match.
+  7. The library in the `TLC` should be loaded when running the application.
+* TC_05
+```
+  PASS : The Launcher_TC_TLC_05 application is normally TLC applied when updating.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Update the application with the `same package ID`.
+  4. The `library(.so)` prior to updating the application should not exist in the `TLC`.
+  5. The `library(.so)` with `same SHA` value updated must exist in the application and TLC.
+  6. The `library(.so)` should be a symbolic link.
+  7. The arch of the target and the arch of the library must match.
+  8. The library in the `TLC` should be loaded when running the application.
+* TC_06
+```
+  PASS : The Launcher_TC_TLC_06 application should not apply TLC when updating.
+```
+  1. There is no `prefer_nuget_cache` metadata in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Update the application with the `same package ID`.
+  4. The `library(.so)` should exist only in the application.
+  5. The `library(.so)` should not be a symbolic link.
+  6. The arch of the target and the arch of the library must match.
+  7. The library in the `application` should be loaded when running the application.
+* TC_07
+```
+  PASS : The Launcher_TC_TLC_07, Launcher_TC_TLC_08 applications using the same nuget are normally TLC applied.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Install two different applications using the `same library`.
+  4. Both applications have a `library(.so)` with `same SHA` value must exist in the application and TLC.
+  5. Both applications have a `library(.so)` should be a symbolic link.
+  6. The arch of the target and the arch of the library must match.
+  7. Uninstall one application.
+  8. All previous library must exist.
+  9. The library in the `TLC` should be loaded when running the application.
+* TC_08
+```
+  PASS : The Launcher_TC_TLC_09 application is normally TLC applied when uninstall.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. Install the application.
+  4. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  5. The `library(.so)` should be a symbolic link.
+  6. The arch of the target and the arch of the library must match.
+  7. Uninstall the application.
+  8. The `library(.so)` should not exist in the `TLC`.
+* TC_09
+```
+  PASS : The Launcher_TC_TLC_10 application should match the information of nuget with the value of TLC database.
+```
+  1. The `prefer_nuget_cache` metadata value is `true` in the manifest.
+  2. The nuget used has a TFM folder related to Tizen.
+  3. The `library(.so)` with `same SHA` value must exist in the application and TLC.
+  4. The `library(.so)` should be a symbolic link.
+  5. The arch of the target and the arch of the library must match.
+  6. The information in `library(.so)` must match the `TAC database` value.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/5_TLC/TLC.py b/tests/TCs/5_TLC/TLC.py
new file mode 100755 (executable)
index 0000000..66cb913
--- /dev/null
@@ -0,0 +1,579 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from pathlib import Path
+from Utils import *
+
+
+module_name = "TLC"
+
+# The `Launcher_TC_TLC_01` application must have TLC applied.
+def TC_01():
+    sln_name = "Launcher_TC_TLC_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." + sha) not in raw:
+        return "FAIL : TThe libSkiaSharp.so library in the TLC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_02` application must have TLC applied.
+def TC_02():
+    sln_name = "Launcher_TC_TLC_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." + sha) not in raw:
+        return "FAIL : The libSkiaSharp.so library in the TLC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_03` application should not apply TLC when updating.
+def TC_03():
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    sln_name = "Launcher_TC_TLC_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha in raw:
+        return f"FAIL : The libSkiaSharp.so library should not exist in {DOTNET_DIR}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name libSkiaSharp.so")
+    if f"{root_path}/bin/libSkiaSharp.so" in raw:
+        return "FAIL : The libSkiaSharp.so library should not exist in the application"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." in raw:
+        return "FAIL : The libSkiaSharp.so library should not be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# It should be done together for update test.
+def TC_02_03():
+    ret = TC_02()
+    if "PASS" != ret:
+        return f"{ret}"
+
+    ret = TC_03()
+    if  "PASS" != ret:
+        return f"{ret}"
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_04` application is normally TLC applied when updating.
+def TC_04():
+    sln_name = "Launcher_TC_TLC_04.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." + sha) not in raw:
+        return "FAIL : The libSkiaSharp.so library in the TLC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_05` application is normally TLC applied when updating.
+def TC_05():
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    sln_name = "Launcher_TC_TLC_05.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha in raw:
+        return f"FAIL : The libSkiaSharp.so library should not exist in {DOTNET_DIR}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." + sha) not in raw:
+        return "FAIL : The libSkiaSharp.so library in the TLC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# It should be done together for update test.
+def TC_04_05():
+    ret = TC_04()
+    if "PASS" != ret:
+        return f"{ret}"
+
+    ret = TC_05()
+    if  "PASS" != ret:
+        return f"{ret}"
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_06` application should not apply TLC when updating.
+def TC_06():
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    sln_name = "Launcher_TC_TLC_06.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha in raw:
+        return f"FAIL : The libSkiaSharp.so library should not exist in {DOTNET_DIR}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if f"{root_path}/bin/libSkiaSharp.so" not in raw:
+        return "FAIL : The libSkiaSharp.so library should exist only"
+    if "->" in raw:
+        return "FAIL : The libSkiaSharp.so library should not be a symbolic link"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libSkiaSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." in raw) or \
+       (f"{root_path}/bin/libSkiaSharp.so" not in raw):
+        return "FAIL : The libSkiaSharp.so library in the application should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# It should be done together for update test.
+def TC_04_05_06():
+    ret = TC_04()
+    if "PASS" != ret:
+        return f"{ret}"
+
+    ret = TC_05()
+    if  "PASS" != ret:
+        return f"{ret}"
+
+    ret = TC_06()
+    if "PASS" != ret:
+        return f"{ret}"
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_07`, `Launcher_TC_TLC_08` applications using the same nuget are normally TLC applied.
+def TC_07():
+    sln_name = "Launcher_TC_TLC_07.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id1 = f"org.tizen.example.Launcher_TC_TLC_07.Tizen"
+
+    root_path = get_root_path(f"{pkg_id1}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id1}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libHarfBuzzSharp.so")
+    if (f"{root_path}/bin/libHarfBuzzSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libHarfBuzzSharp.so.." not in raw):
+        return "FAIL : The libHarfBuzzSharp.so library should exist or be a symbolic link"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libHarfBuzzSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libHarfBuzzSharp.so library should exist in {DOTNET_DIR}"
+
+    sln_name = "Launcher_TC_TLC_08.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id2 = f"org.tizen.example.Launcher_TC_TLC_08.Tizen"
+
+    root_path = get_root_path(f"{pkg_id2}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id2}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libHarfBuzzSharp.so")
+    if f"{root_path}/bin/libHarfBuzzSharp.so" not in raw:
+        return "FAIL : The libHarfBuzzSharp.so library should exist"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libHarfBuzzSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"uninstall {pkg_id1}")
+    if "key[end] val[ok]" not in raw:
+        return f"FAIL : Uninstall the application for {pkg_id1}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libHarfBuzzSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libHarfBuzzSharp.so library should exist in {DOTNET_DIR}"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libHarfBuzzSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id2}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id2}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep libHarfBuzzSharp.so")
+    if (f"{DOTNET_DIR}Libraries/libHarfBuzzSharp.so.." + sha) not in raw:
+        return "FAIL : The libHarfBuzzSharp.so library in the TLC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id2}")
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_09` application is normally TLC applied when uninstall.
+def TC_08():
+    sln_name = "Launcher_TC_TLC_09.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_09.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/libSkiaSharp.so")
+    if (f"{root_path}/bin/libSkiaSharp.so" not in raw) or \
+       (f"{DOTNET_DIR}Libraries/libSkiaSharp.so.." not in raw):
+        return "FAIL : The libSkiaSharp.so library should exist or be a symbolic link"
+
+    if "OK" not in check_library_arch(f"{root_path}", "libSkiaSharp.so"):
+        return "FAIL : The arch of the target and the arch of the library must match"
+
+    sha = raw.split("..")[1].rstrip()
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha not in raw:
+        return f"FAIL : The libSkiaSharp.so library should exist in {DOTNET_DIR}"
+
+    raw = cmd(f"uninstall {pkg_id}")
+    if "key[end] val[ok]" not in raw:
+        return f"FAIL : Uninstall the application for {pkg_id}"
+
+    raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name libSkiaSharp.so*")
+    if sha in raw:
+       return f"FAIL : The libSkiaSharp.so library should not exist in {DONTET_DIR}"
+
+    return "PASS"
+
+# The `Launcher_TC_TLC_10` application should match the information of nuget with the value of TLC database.
+def TC_09():
+    sln_name = "Launcher_TC_TLC_10.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TLC_10.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name lib*.so*")
+    lines1 = [l for l in raw.splitlines()]
+    if len(lines1) == 0:
+        return "FAIL : The library should exist in the application"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {DOTNET_DIR}.TLC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TLC;\n.q\n", encoding="utf-8").stdout
+    lines2 = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    if len(lines2) == 0:
+        return "FAIL : TLC database must have a valid value"
+
+    for lib in lines1:
+        raw = cmd(f"shell ls -alZ {lib}")
+        if "->" not in raw:
+            return f"FAIL : The {name} library should be a symbolic link"
+
+        name = Path(lib).name
+        if "OK" not in check_library_arch(f"{root_path}", f"{name}"):
+            return "FAIL : The arch of the target and the arch of the library must match"
+
+        sha = raw.split("..")[1].rstrip()
+
+        raw = cmd(f"shell find {DOTNET_DIR}Libraries/ -name {name}..{sha}")
+        if f"{DOTNET_DIR}Libraries/{name}..{sha}" not in raw:
+            return f"FAIL : The {name} library should exist in {DOTNET_DIR}"
+
+        is_exist = False
+        for rcd in lines2:
+            if f"{name}..{sha}" in raw:
+                is_exist = True
+                break
+
+        if not is_exist:
+            return "FAIL : TLC database must have a valid value"
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_00.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_07.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_08.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_09.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_10.Tizen")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_02_03, 'TC_04': TC_04, 'TC_05': TC_04_05, 'TC_06': TC_04_05_06, 'TC_07': TC_07, 'TC_08': TC_08, 'TC_09': TC_09,
+'TLC_TC_01': TC_01, 'TLC_TC_02': TC_02, 'TLC_TC_03': TC_02_03, 'TLC_TC_04': TC_04, 'TLC_TC_05': TC_04_05,
+'TLC_TC_06': TC_04_05_06, 'TLC_TC_07': TC_07, 'TLC_TC_08': TC_08, 'TLC_TC_09': TC_09
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/6_TOOL/README.md b/tests/TCs/6_TOOL/README.md
new file mode 100644 (file)
index 0000000..a27cd5f
--- /dev/null
@@ -0,0 +1,119 @@
+# Test Case for dotnet-launcher - DOTNETTOOL
+
+This script(TOOL.py) is a test that verifies the behavior of **dotnettool**.
+Check each option of the dotnettool.
+```
+sh-3.2# dotnettool -h
+
+Dotnet Tool Version: 1.0
+...
+```
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **DOTNETTOOL** test
+```
+launcher/tests/TCs$ ./6_TOOL/TOOL.py
+launcher/tests/TCs/6_TOOL$ ./TOOL.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/6_TOOL$ ./TOOL.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : The dotnettool works normally.
+```
+  1. sh-3.2# dotnettool -h
+* TC_02
+```
+  PASS : The native image is generated normally.
+```
+  1. sh-3.2# dotnettool --ni-system
+* TC_03
+```
+  PASS : Remove the platform native image.
+```
+  1. sh-3.2# dotnettool --ni-reset-system
+* TC_04
+```
+  PASS : Create native image for System.Private.CoreLib.dll.
+```
+  1. sh-3.2# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll
+* TC_05
+```
+  PASS : The file name of .dll and .ni.dll must match in the framework.
+```
+  1. sh-3.2# dotnettool --ni-dir /usr/share/dotnet.tizen/framework/
+* TC_06
+```
+  PASS : The .ni.dll files should not exist in the framework.
+```
+  1. sh-3.2# dotnettool --ni-reset-dir /usr/share/dotnet.tizen/framework/
+* TC_07
+```
+  PASS : Create native image for Tizen.dll in R2Rmode.
+```
+  1. sh-3.2# dotnettool --r2r --ni-dll /usr/share/dotnet.tizen/framework/Tizen.dll
+* TC_08
+```
+  PASS : The Launcher_TC_TOOL_01 application does not have native image.
+```
+  1. sh-3.2# dotnettool --ni-reset-pkg org.tizen.example.Launcher_TC_TOOL_01.Tizen
+* TC_09
+```
+  PASS : The Launcher_TC_TOOL_02 application generates native image.
+```
+  1. sh-3.2# dotnettool --ni-pkg org.tizen.example.Launcher_TC_TOOL_02.Tizen
+* TC_10
+```
+  PASS : The prefer_dotnet_aot metadata value of true will regenerates the native image in all .NET applications.
+```
+  1. sh-3.2# dotnettool --ni-regen-all-app
+* TC_11
+```
+  PASS : The prefer_nuget_cache metadata value of true will regenerates the native image in the TAC.
+```
+  1. sh-3.2# dotnettool --tac-regen-all
+* TC_12
+```
+  PASS : The Launcher_TC_TOOL_05 application must not have TAC applied.
+```
+  1. sh-3.2# dotnettool --tac-disable-pkg org.tizen.example.Launcher_TC_TOOL_05.Tizen
+* TC_13
+```
+  PASS : The Launcher_TC_TOOL_06 application must have TAC applied.
+```
+  1. sh-3.2# dotnettool --tac-enable-pkg org.tizen.example.Launcher_TC_TOOL_06.Tizen
+* TC_14
+```
+  PASS : The Database of the restored TAC and TLC must be a valid value.
+```
+  1. sh-3.2# dotnettool --tac-restore-db
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/6_TOOL/TOOL.py b/tests/TCs/6_TOOL/TOOL.py
new file mode 100755 (executable)
index 0000000..82ecb58
--- /dev/null
@@ -0,0 +1,484 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "TOOL"
+
+# The `dotnettool` works normally.
+def TC_01():
+    raw = cmd(f"shell find /usr/bin/ -name dotnettool")
+    if "/usr/bin/dotnettool" not in raw:
+        return "FAIL : The dotnettool works normally"
+
+    raw = cmd(f"shell dotnettool")
+    if "Dotnet Tool Version: 1.0" not in raw:
+        return "FAIL : The dotnettool works normally"
+
+    return "PASS"
+
+# The `native image` is generated normally.
+def TC_02():
+    cmd(f"shell dotnettool --ni-system")
+
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" not in raw:
+        return "FAIL : Create the platform native image"
+
+    raw = cmd(f"shell find {RUNTIME_DIR} -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RUNTIME_DIR} -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if (len(lines1) + 2) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match"
+
+    raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines() if "/ref/" not in l]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match"
+
+    for ni in lines1:
+        is_same = False
+        for dll in lines2:
+            if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                is_same = True
+                break
+        if not is_same:
+            return "FAIL : The file name of .dll and .ni.dll must match in the platform"
+
+    return "PASS"
+
+# Remove the `platform` native image.
+def TC_03():
+    cmd(f"shell dotnettool --ni-reset-system")
+
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" in raw:
+        return "FAIL : Remove the platform native image"
+
+    return "PASS"
+
+# Create native image for `System.Private.CoreLib.dll`.
+def TC_04():
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" in raw:
+        cmd(f"shell rm {RUNTIME_DIR}{SPC_DLL}")
+        cmd(f"shell mv {RUNTIME_DIR}{SPC_DLL}.Backup {RUNTIME_DIR}{SPC_DLL}")
+
+    raw = cmd(f"shell dotnettool --ni-dll {RUNTIME_DIR}{SPC_DLL}")
+    if f"{SPC_DLL} (FNV)" not in raw and \
+       "System.Private.CoreLib.ni.dll generated successfully." not in raw:
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" not in raw:
+        return f"FAIL : Create native image for {SPC_DLL}"
+
+    return "PASS"
+
+# The file name of `.dll` and `.ni.dll` must match in the framework.
+def TC_05():
+    cmd(f"shell dotnettool --ni-dir {FRAMEWORK_DIR}")
+    raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines() if "/ref/" not in l]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match"
+
+    for ni in lines1:
+        is_same = False
+        for dll in lines2:
+            if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                is_same = True
+                break
+        if not is_same:
+            return "FAIL : The file name of .dll and .ni.dll must match in the {FRAMEWORK_DIR}"
+
+    return "PASS"
+
+# The `.ni.dll` files should not exist in the framework.
+def TC_06():
+    cmd(f"shell dotnettool --ni-reset-dir {FRAMEWORK_DIR}")
+    raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The .ni.dll files should not exist"
+
+    return "PASS"
+
+# Create native image for Tizen.dll in `R2R` mode.
+def TC_07():
+    raw = cmd(f"shell dotnettool --r2r --ni-dll {FRAMEWORK_DIR}Tizen.dll")
+    if "Tizen.dll (R2R)" not in raw and \
+       "Tizen.ni.dll generated successfully." not in raw:
+        return "FAIL : Create native image for Tizen.dll in R2R mode"
+
+    return "PASS"
+
+# The `Launcher_TC_TOOL_01` application does not have native image.
+def TC_08():
+    sln_name = "Launcher_TC_TOOL_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TOOL_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" not in raw:
+        return "FAIL : The .native_image folder should exist"
+
+    cmd(f"shell dotnettool --ni-reset-pkg {pkg_id}")
+
+    raw = cmd(f"shell ls {root_path}/bin/.native_image")
+    if "No such file or directory" not in raw:
+        return "FAIL : The .native_image folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The .ni.dll files should not exist"
+
+    return "PASS"
+
+# The `Launcher_TC_TOOL_02` application generates native image.
+def TC_09():
+    sln_name = "Launcher_TC_TOOL_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TOOL_02.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell ls {root_path}/bin/.native_image")
+    if "No such file or directory" not in raw:
+        return "FAIL : The .native_image folder not should exist"
+
+    cmd(f"shell dotnettool --ni-pkg {pkg_id}")
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .native_image")
+    if ".native_image" not in raw:
+        return "FAIL : The .native_image folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.native_image/ -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll and .ni.dll must match in the application"
+
+    for ni in lines1:
+        is_same = False
+        for dll in lines2:
+            if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                is_same = True
+                break
+        if not is_same:
+            return "FAIL : The file name of .dll and .ni.dll must match in the application"
+
+    return "PASS"
+
+# The `prefer_dotnet_aot` metadata value of `true` will regenerates the native image in all .NET applications.
+def TC_10():
+    sln_name = "Launcher_TC_TOOL_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    cmd(f"shell dotnettool --ni-regen-all-app")
+
+    raw = subprocess.run((f"sdb -s {serial} shell pkginfo --metadata-flt").split(), stdout=subprocess.PIPE, input=f"http://tizen.org/metadata/prefer_dotnet_aot\ntrue\n", encoding="utf-8").stdout
+    lines1 = [l for l in raw.splitlines() if "appid" in l]
+    lines2 = []
+    for app in lines1:
+        pkg_id = app.split(": ")[1]
+        raw = subprocess.run((f"sdb -s {serial} shell pkginfo --pkg {pkg_id}").split(), stdout=subprocess.PIPE, encoding="utf-8").stdout
+        lines2 = [l for l in raw.splitlines() if "root_path" in l]
+
+    for path in lines2:
+        root_path = path.split(": ")[1]
+        raw = cmd(f"shell find {root_path}/bin/.native_image/ -name *.ni.dll")
+        lines3 = [l for l in raw.splitlines()]
+        raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+        lines4 = [l for l in raw.splitlines()]
+        if len(lines3) != len(lines4):
+            return "FAIL : The number of .dll and .ni.dll must match in the application"
+
+        for ni in lines3:
+            is_same = False
+            for dll in lines4:
+                if Path(ni).name.replace(".ni.dll", "") == Path(dll).name.replace(".dll", ""):
+                    is_same = True
+                    break
+            if not is_same:
+                return "FAIL : The file name of .dll and .ni.dll must match in the application"
+
+    return "PASS"
+
+# The `prefer_nuget_cache` metadata value of `true` will regenerates the native image in the `TAC`.
+def TC_11():
+    sln_name = "Launcher_TC_TOOL_04.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    raw = cmd(f"shell dotnettool --tac-regen-all")
+    if ".dll (FNV)" not in raw and \
+       ".ni.dll generated successfully." not in raw:
+        return "FAIL : Create native image for TAC"
+
+    return "PASS"
+
+# The `Launcher_TC_TOOL_05` application must not have `TAC` applied.
+def TC_12():
+    sln_name = "Launcher_TC_TOOL_05.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TOOL_05.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.6.0.967/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    cmd(f"shell dotnettool --tac-disable-pkg {pkg_id}")
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" in raw:
+        return "FAIL : The .tac_symlink folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 6:
+        return "FAIL : The number of .dll must exist correctly in the bin folder"
+
+    return "PASS"
+
+# The `Launcher_TC_TOOL_06` application must have `TAC` applied.
+def TC_13():
+    sln_name = "Launcher_TC_TOOL_06.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TOOL_06.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    cmd(f"shell dotnettool --tac-disable-pkg {pkg_id}")
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" in raw:
+        return "FAIL : The .tac_symlink folder should not exist"
+
+    raw = cmd(f"shell find {root_path}/bin/ -maxdepth 1 -name *.dll -not -name *.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 6:
+        return "FAIL : The number of .dll must exist correctly in the bin folder"
+
+    cmd(f"shell dotnettool --tac-enable-pkg {pkg_id}")
+
+    raw = cmd(f"shell find {root_path}/bin/ -name .tac_symlink")
+    if ".tac_symlink" not in raw:
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {DOTNET_DIR}Xamarin.Forms/4.6.0.967/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        raw = cmd(f"shell ls -alZ {origin_path}")
+        if "No such file or directory" in raw:
+            return "FAIL : The original file of the symbolic link must exist"
+
+    return "PASS"
+
+# The `DB` of the restored `TAC` and `TLC` must be a valid value.
+def TC_14():
+    sln_name = "Launcher_TC_TOOL_07.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    cmd(f"shell rm {DOTNET_DIR}.TAC.App.list.db*")
+    cmd(f"shell rm {DOTNET_DIR}.TLC.App.list.db*")
+
+    cmd(f"shell dotnettool --tac-restore-db")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TOOL_07.Tizen"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {DOTNET_DIR}.TAC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TAC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for rcd in lines:
+        if ("SkiaSharp/2.80.2" not in rcd) and \
+           ("Xamarin.Forms/4.6.0.967" not in rcd):
+            return "FAIL : TAC database must have a valid value"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {DOTNET_DIR}.TLC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TLC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for rcd in lines:
+        if "libSkiaSharp.so..8e2fcc43f9c49b2de7b6212ff5ed914b319bc92f125715b9fe1f35786df82f98" not in rcd:
+            return "FAIL : TLC database must have a valid value"
+
+    return "PASS"
+
+
+#def TC_15():
+#dotnettool --resolve-all-app
+
+#def TC_16():
+#dotnettool --ibc-dir
+
+#def TC_17():
+#dotnettool --instrument
+
+#def TC_18():
+#dotnettool --compatibility
+
+#def TC_19():
+#dotnettool --verbose
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_02.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_03.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_04.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_05.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_06.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_07.Tizen")
+
+    cmd(f"shell rm {FRAMEWORK_DIR}Tizen.ni.dll")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09, TC_10, TC_11, TC_12, TC_13, TC_14]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05, 'TC_06': TC_06, 'TC_07': TC_07,
+'TC_08': TC_08, 'TC_09': TC_09, 'TC_10': TC_10, 'TC_11': TC_11, 'TC_12': TC_12, 'TC_13': TC_13, 'TC_14': TC_14,
+'TOOL_TC_01': TC_01, 'TOOL_TC_02': TC_02, 'TOOL_TC_03': TC_03, 'TOOL_TC_04': TC_04, 'TOOL_TC_05': TC_05, 'TOOL_TC_06': TC_06, 'TOOL_TC_07': TC_07,
+'TOOL_TC_08': TC_08, 'TOOL_TC_09': TC_09, 'TOOL_TC_10': TC_10, 'TOOL_TC_11': TC_11, 'TOOL_TC_12': TC_12, 'TOOL_TC_13': TC_13, 'TOOL_TC_14': TC_14
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/7_LAUNCH/LAUNCH.py b/tests/TCs/7_LAUNCH/LAUNCH.py
new file mode 100755 (executable)
index 0000000..8537283
--- /dev/null
@@ -0,0 +1,249 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "LAUNCH"
+
+# The `Launcher_TC_LAUNCH_01` application should run in `candidate(dotnet-loader)` mode.
+def TC_01():
+    sln_name = "Launcher_TC_LAUNCH_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_LAUNCH_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if "OK" not in prepare_candidate_process(f"dotnet-loader", f"{pkg_id}"):
+        return f"FAIL : Candidate process should have dotnet-loader"
+
+    pid = launch_and_get_pid(f"-s", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_LAUNCH_01.Tizen")
+    if f"{root_path}/bin/Launcher_TC_LAUNCH_01.Tizen.dll" not in raw:
+        return "FAIL : The application is run as a candidate mode."
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_LAUNCH_01` application should run in `standalone(dotnet-launcher)` mode.
+def TC_02():
+    sln_name = "Launcher_TC_LAUNCH_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_LAUNCH_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_LAUNCH_01.Tizen")
+    if f"{root_path}/bin/Launcher_TC_LAUNCH_01.Tizen.dll" not in raw:
+        return "FAIL : The application is run as a standalone mode"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_LAUNCH_02` application should run in `candidate(dotnet-nui-loader)` mode.
+def TC_03():
+    sln_name = "Launcher_TC_LAUNCH_02"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_LAUNCH_02"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if "OK" not in prepare_candidate_process(f"dotnet-nui-loader", f"{pkg_id}"):
+        return f"FAIL : Candidate process should have dotnet-nui-loader"
+
+    pid = launch_and_get_pid(f"-s", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_LAUNCH_02")
+    if f"{root_path}/bin/Launcher_TC_LAUNCH_02.dll" not in raw:
+        return "FAIL : The application is run as a candidate mode"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_LAUNCH_03` application should run in `hydra(dotnet-hydra-loader)` mode.
+def TC_04():
+    sln_name = "Launcher_TC_LAUNCH_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_LAUNCH_03.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"pull /usr/share/aul/dotnet.loader dotnet.loader.origin")
+    if "1 file(s) pulled. 0 file(s) skipped." not in raw:
+        return "FAIL : Pull the dotnet.loader file from the target"
+
+    f1 = open("./dotnet.loader", "w")
+    f2 = open("./dotnet.loader.origin", "r")
+
+    for line in f2:
+        if line.startswith("EXE "):
+            f1.write(line.replace("EXE", "#EXE"))
+        elif line.startswith("#EXE "):
+            f1.write(line.replace("#EXE", "EXE"))
+        elif line.startswith("HYDRA "):
+            f1.write(line.replace("OFF", "ON"))
+        else:
+            f1.write(line)
+    f2.close()
+    f1.close()
+
+    raw = cmd(f"push dotnet.loader /usr/share/aul/")
+    if "1 file(s) pushed. 0 file(s) skipped." not in raw:
+        return "FAIL : Push the dotnet.loader file to the target"
+
+    cmd(f"shell chsmack -a _ /usr/share/aul/dotnet.loader")
+    cmd(f"shell chmod 644 /usr/share/aul/dotnet.loader")
+
+    cmd(f"shell reboot -f")
+    sleep(30)
+
+    if "." in serial:
+        subprocess.run((f"sdb connect {serial}").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    if "OK" not in prepare_candidate_process(f"dotnet-loader", f"{pkg_id}"):
+        return f"FAIL : Candidate process should have dotnet-loader"
+
+    raw = cmd(f"shell ps -ef | grep dotnet-hydra-loader")
+    if "/usr/bin/dotnet-hydra-loader" not in raw:
+        return "FAIL : Candidate process should have dotnet-hydra-loader"
+
+    pid = launch_and_get_pid(f"-s", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_LAUNCH_03.Tizen")
+    if f"{root_path}/bin/Launcher_TC_LAUNCH_03.Tizen.dll" not in raw:
+        return "FAIL : The application is run as a candidate mode"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    p = run_tc_array(module_name, tc_array)
+    f = len(tc_array) - p
+    r = round(((p / len(tc_array)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nFAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_LAUNCH_01.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_LAUNCH_02")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_LAUNCH_03.Tizen")
+
+    cmd(f"shell mount -o remount,rw /")
+    cmd(f"push dotnet.loader.origin /usr/share/aul/dotnet.loader")
+    cmd(f"shell chsmack -a _ /usr/share/aul/dotnet.loader")
+    cmd(f"shell chmod 644 /usr/share/aul/dotnet.loader")
+    cmd(f"shell reboot -f")
+
+    subprocess.run((f"rm dotnet.loader").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+    subprocess.run((f"rm dotnet.loader.origin").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04,
+'LAUNCH_TC_01': TC_01, 'LAUNCH_TC_02': TC_02, 'LAUNCH_TC_03': TC_03, 'LAUNCH_TC_04': TC_04
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
diff --git a/tests/TCs/7_LAUNCH/README.md b/tests/TCs/7_LAUNCH/README.md
new file mode 100644 (file)
index 0000000..849121f
--- /dev/null
@@ -0,0 +1,75 @@
+# Test Case for dotnet-launcher - LAUNCH
+
+This script(LAUNCH.py) is a test that verifies the behavior of **application launch**.
+Check the candidate, standalone and hydra mode.
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run **LAUNCH** test
+```
+launcher/tests/TCs$ ./7_LAUNCH/LAUNCH.py
+launcher/tests/TCs/7_LAUNCH$ ./LAUNCH.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/7_LAUNCH$ ./LAUNCH.py TC_01
+```
+
+### Description
+* TC_01
+```
+  PASS : The Launcher_TC_LAUNCH_01 application should run in candidate(dotnet-loader) mode.
+```
+  1. Candidate process should have dotnet-loader.
+  2. Excute the application.
+  3. Get the pid value.
+  4. The application is run as a candidate mode.
+* TC_02
+```
+  PASS : The Launcher_TC_LAUNCH_01 application should run in standalone(dotnet-launcher) mode.
+```
+  1. Excute the application without the dotnet-loader.
+  2. Get the pid value.
+  3. The application is run as a standalone mode.
+* TC_03
+```
+  PASS : The Launcher_TC_LAUNCH_02 application should run in candidate(dotnet-nui-loader) mode.
+```
+  1. Candidate process should have dotnet-nui-loader.
+  2. Excute the application.
+  3. Get the pid value.
+  4. The application is run as a candidate mode.
+* TC_04
+```
+  PASS : The Launcher_TC_LAUNCH_03 application should run in hydra(dotnet-hydra-loader) mode.
+```
+  1. Modify the dotnet.loader file.
+  2. Candidate process should have dotnet-hydra-loader.
+  3. Excute the application.
+  4. Get the pid value.
+  5. The application is run as a candidate mode.
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/ALL.py b/tests/TCs/ALL.py
new file mode 100755 (executable)
index 0000000..e6ae958
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+import os, subprocess, sys
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+script_lists = []
+def get_script_path(dirname):
+    filenames = os.listdir(dirname)
+    for filename in filenames:
+        full_filename = os.path.join(dirname, filename)
+        if os.path.isdir(full_filename):
+            get_script_path(full_filename)
+        else:
+            ext = os.path.splitext(full_filename)[-1]
+            if ext == ".py" and \
+               "BuildTPK" not in full_filename and \
+               "Utils" not in full_filename and \
+               "ALL" not in full_filename:
+                script_lists.append(full_filename)
+    return script_lists
+
+
+def run(serial):
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case ===")
+
+    for tc in sorted(script_lists):
+        subprocess.run((f"{tc} {serial}").split())
+        sleep(3)
+
+
+def main():
+    serial = read_serial(None)
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    get_script_path("./")
+    run(serial)
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        exit(1)
diff --git a/tests/TCs/README.md b/tests/TCs/README.md
new file mode 100644 (file)
index 0000000..c4c480e
--- /dev/null
@@ -0,0 +1,53 @@
+# Test Case for dotnet-launcher
+
+The dotnet-launcher dosen't provide APIs, so there is no test case in TCT.
+So, We provide the test case to check the functionality of the dotnet-launcher.
+
+### Usage
+
+* Build tpk
+
+  Must be run(./BuildTPK.py) at least once.
+```
+launcher/tests/Apps$ ./BuildTPK.py
+```
+
+* Run full test
+```
+launcher/tests/TCs$ ./ALL.py
+```
+
+* Run each test
+```
+launcher/tests/TCs/1_AOT$ ./AOT.py
+launcher/tests/TCs/2_PLUGIN$ ./PLUGIN.py
+launcher/tests/TCs/3_RELOAD$ ./PRELOAD.py
+launcher/tests/TCs/4_TAC$ ./TAC.py
+launcher/tests/TCs/5_TLC$ ./TLC.py
+launcher/tests/TCs/6_TOOL$ ./TOOL.py
+launcher/tests/TCs/7_LAUNCH$ ./LAUNCH.py
+```
+
+* Run individual test
+```
+launcher/tests/TCs/1_AOT$ ./AOT.py TC_01
+launcher/tests/TCs/6_TOOL$ ./TOOL.py TC_04 TC_05
+```
+
+----
+
+### Note
+
+* Precondition
+  - Clone the **dotnet-launcher** repository.
+  - The prerequisites are **sdb** and **python3.6+**.
+  - The script must be run on the **host PC**.
+
+* SDBs
+
+    sdb with a smart device selector.
+```
+[1] 192.168.250.250 - 0
+[2] 002c02f56c7d6c66 - TW3
+Select a device [1-2]: 2
+```
diff --git a/tests/TCs/Utils.py b/tests/TCs/Utils.py
new file mode 100755 (executable)
index 0000000..cbd824b
--- /dev/null
@@ -0,0 +1,178 @@
+#!/usr/bin/env python3
+import os, subprocess, sys
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from pathlib import Path
+
+# Defined paths
+RUNTIME_DIR = "/usr/share/dotnet.tizen/netcoreapp/"
+FRAMEWORK_DIR = "/usr/share/dotnet.tizen/framework/"
+PRELOAD_DIR = "/usr/share/dotnet.tizen/preload/"
+DOTNET_DIR = "/opt/usr/dotnet/"
+OWNER_DIR = "/home/owner/"
+SPC_DLL = "System.Private.CoreLib.dll"
+
+# Check the sdb connection status and get a device serial number
+def read_serial(serial):
+    global serial_num
+
+    if serial is not None:
+        serial_num = serial
+        return serial_num
+
+    raw = subprocess.run("sdb devices".split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+    lines = [l for l in raw.splitlines() if not l.startswith("* ")]
+    if len(lines) <= 1:
+        serial_num = None
+    elif len(lines) == 2:
+        serial_num = lines[1].split("  ")[0].split(":")[0].strip()
+    else:
+        serials = []
+        for idx in range(1, len(lines)):
+            serial = lines[idx].split("        ")[0].split(":")[0].replace("device", "").strip()
+            serials.append(serial)
+            print(f"[{idx}] {serial} - {lines[idx].split('     ')[2].strip()}")
+        choice = input(f"Select a device [1-{len(lines) - 1}]: ")
+        serial_num = serials[int(choice) - 1].strip() if choice.isdigit() else None
+    return serial_num
+
+# Execute a command and return the output as a string.
+def cmd(command):
+    return subprocess.run((f"sdb -s {serial_num} " + command).split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+
+# Search the generated .tpk
+tpk_lists = []
+def search_tpk(module, dirname=None):
+    if dirname == None:
+        if os.path.isdir(os.path.join(os.getcwd(), "../../Apps")):
+            dirname = "../../Apps"
+        elif os.path.isdir(os.path.join(os.getcwd(), "../Apps")):
+            dirname = "../Apps"
+        elif os.path.isdir(os.path.join(os.getcwd(), "./Apps")):
+            dirname = "./Apps"
+        else:
+            dirname = "./tests/Apps"
+
+    filenames = os.listdir(dirname)
+    for filename in filenames:
+        full_filename = os.path.join(dirname, filename)
+        if os.path.isdir(full_filename):
+            search_tpk(module, full_filename)
+        else:
+            ext = os.path.splitext(full_filename)[-1]
+            if ext == ".tpk" and f"{module}" in full_filename:
+                tpk_lists.append(full_filename)
+    return tpk_lists
+
+# Get the .tpk path
+def get_tpk_path(tpk_list, sln_name):
+    for tpk in tpk_list:
+        if sln_name in tpk:
+            return tpk
+    return None
+
+# Install the application
+def app_install(tpk_path):
+    raw = cmd(f"push {tpk_path} {OWNER_DIR}")
+    if "1 file(s) pushed. 0 file(s) skipped." not in raw:
+        return "FAIL"
+
+    tpk_name = Path(tpk_path).name
+    raw = cmd(f"shell pkgcmd -i -t tpk -p {OWNER_DIR}{tpk_name}")
+    if "key[end] val[ok]" not in raw:
+        return "FAIL"
+    return "OK"
+
+# Get the root path of the application
+def get_root_path(pkg_id):
+    raw = cmd(f"shell pkginfo --pkg {pkg_id} | grep root_path")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) == 0:
+        return "None"
+    return raw.split(": ")[1].strip()
+
+# Application launch and get the pid
+def launch_and_get_pid(mode, app_id):
+    raw = cmd(f"shell app_launcher {mode} {app_id}")
+    sleep(3)
+    if "successfully launched pid" not in raw:
+        return 0
+    return raw[raw.index("pid") + 6:raw.index("with") - 1]
+
+# Get the device type
+def get_device_type():
+    raw = cmd(f"shell cat /etc/config/model-config.xml | grep tizen.org/system/device_type")
+    return raw.split(">")[1].split("<")[0]
+
+# Create the System.Private.CoreLib native image
+def create_spc_ni():
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" not in raw:
+        raw = cmd(f"shell dotnettool --ni-dll {RUNTIME_DIR}{SPC_DLL}")
+        if "System.Private.CoreLib.ni.dll generated successfully." not in raw:
+            return "FAIL"
+
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" not in raw:
+        return "FAIL"
+    return "OK"
+
+# Remove the platform native image
+def remove_system_ni():
+    cmd(f"shell dotnettool --ni-reset-system")
+    raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
+    if f"{RUNTIME_DIR}{SPC_DLL}.Backup" in raw:
+        return "FAIL"
+    return "OK"
+
+# Prepare the candidate process
+def prepare_candidate_process(loader, pkg_id):
+    cmd(f"shell killall dotnet-launcher {loader}")
+    sleep(30)
+
+    raw = cmd(f"shell ps -ef | grep {loader}")
+    if f"/usr/bin/{loader}" not in raw:
+        cmd(f"shell app_launcher -s {pkg_id}")
+        sleep(30)
+        cmd(f"shell app_launcher -t {pkg_id}")
+
+    raw = cmd(f"shell ps -ef | grep {loader}")
+    if f"/usr/bin/{loader}" not in raw:
+        return "FAIL"
+
+    pid = raw.split()[1]
+    return f"OK : {pid}"
+
+# Check the library type
+def check_library_arch(rootpath, library):
+    raw = cmd(f"pull {rootpath}/bin/{library} {library}")
+    if "1 file(s) pulled. 0 file(s) skipped." not in raw:
+        return "FAIL"
+
+    raw = cmd("capability")
+    line = [l for l in raw.splitlines() if "cpu_arch" in l]
+    target_arch = line[0].split(":")[1]
+    raw = subprocess.run((f"file ./{library}").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+    if "armv7" == target_arch:
+        if "ARM" not in raw:
+            return "FAIL"
+    elif "x86" == target_arch:
+        if "Intel 80386" not in raw:
+            return "FAIL"
+    else:
+        return "FAIL"
+
+    subprocess.run((f"rm ./{library}").split(), encoding="utf-8", stdout=subprocess.PIPE).stdout
+    return "OK"
+
+# Run the test array
+def run_tc_array(module_name, tc_array):
+    p = 0
+    for tc in tc_array:
+        print(f">{module_name}_{tc.__name__}...", end="\r")
+        ret = tc()
+        print(f">{module_name}_{tc.__name__} : {ret}")
+        if "PASS" == ret: p += 1
+        sleep(3)
+    return p