12.13.2017

getopt_long()測試方法-A

在上一篇文章當中─Linux C getopt_long(),只有初步地提到為何需要這樣的函式?這個函式是如何地宣告?然後再加上自己寫的一個簡單範例。

在程式碼的撰寫過程當中,不可能一開始就寫得很複雜,一定是從簡單地判斷開始去做,發現有問題,就慢慢的一步一步堆疊上去。

1. 長選項,和短選項,先分開來測;
2. 每一個選項,我都挑2個選項來測;所以會有2種組合;
3. 因為在實務上,不太可能只接1個選項,可能是2個選項、3個選項,所以測試時,就以1個選項2個選項來做為測試方法,所以也會有2種組合;
4. 因為選項後面,又可以再區分為有帶參數沒帶參數,也是2種組合。
5. 綜合2~5點,我們會有2 * 2 * 2 = 8種組合。為了方便起見,所有選項後面的參數,就用12345678來表示。

getopt_long()函式所傳進去的第4個引數const struct option *longopts,是一個option的結構陣列;option結構的第2個成員int has_arg; 是決定這一個長選項是否要帶參數。從這一個差異點來著手,自己的測試命令列指令是:

Step I: 長選項的has_arg為沒有參數 (0: no_argument)時:
01. ./main --author
02. ./main --force
03. ./main --author 1234
04. ./main --force 5678
05. ./main --author --force
06. ./main --author --force 5678
07. ./main --author 1234 --force
08. ./main --author 1234 --force 5678

Step II: 長選項的has_arg為必有參數 (1: required_argument)時:
09. ./main --add
10. ./main --append
11. ./main --add 1234
12. ./main --append 5678
13. ./main --add --append
14. ./main --add --append 5678
15. ./main --add 1234 --append
16. ./main --add 1234 --append 5678

Step III: 長選項的has_arg為可有參數 (2: optional_argument)時:
17. ./main --all
18. ./main --file
19. ./main --all 1234
20. ./main --file 5678
21. ./main --all --file
22. ./main --all --file 5678
23. ./main --all 1234 --file
24. ./main --all 1234 --file 5678

長選項的部份完成之後,再來看短選項的部份,也就是getopt_long()的第3個引數const char *optstring

在這個引數當中,若選項後面沒有接冒號表沒有參數;反之則為必有參數。

Step IV: 短選項沒有參數 ()時:
25. ./main -X
26. ./main -Y
27. ./main -X 1234
28. ./main -Y 5678
29. ./main -X -Y
30. ./main -X -Y 5678
31. ./main -X 1234 -Y
32. ./main -X 1234 -Y 5678

Step V: 短選項必有參數 (:)時:
33. ./main -x
34. ./main -y
35. ./main -x 1234
36. ./main -y 5678
37. ./main -x -y
38. ./main -x -y 5678
39. ./main -x 1234 -y
40. ./main -x 1234 -y 5678

以上的5大項,都是在理想化的狀態之下做的實驗和測試;倘若使用者輸入不存在的選項呢?是否應該也要有相對應的防呆機制?

Step VI: 輸入一個不存在的長選項時:
41. ./main --ask
42. ./main --oops
43. ./main --ask 1234
44. ./main --oops 5678
45. ./main --ask --oops
46. ./main --ask --oops 5678
47. ./main --ask 1234 --oops
48. ./main --ask 1234 --oops 5678

Step VII: 輸入一個不存在的短選項時:
49. ./main -Q
50. ./main -r
51. ./main -Q 1234
52. ./main -r 5678
53. ./main -Q -r
54. ./main -Q -r 5678
55. ./main -Q 1234 -r
56. ./main -Q 1234 -r 5678

從Step I ~ VII的測試項目當中,不難發現:

a). getopt_long()函式在判斷命令列參數時,是以每一個參數是否為"--"或是'-'開頭。

b). 若為"--"開頭,表示長選項;有找到相對應的長選項,getopt_long()會回傳0。

c). 若為'-'開頭,表示短選項;有找到相對應的短選項,getopt_long()會回傳該字元。

d). 若連續2個選項寫在一起,如:"--author --force", "--author -Y", "-X --force", "-X -Y"等等,getopt_long()函式並不會判斷這是2個不同的選項;而是會判斷成"--force"是"--author"的參數。所以這一部份必須由程式設計師們去做一個防呆的判斷。

e). 無論長短選項,選項後面需要接上參數,而沒有接時,getopt_long()會回傳'?'字元。

f). 若是輸入不存在選項時,getopt_long()也會回傳'?'字元。

g). 綜合e). 和f). ,至於是何種原因導致getopt_long()回傳'?'字元,這也是由程式設計師來判斷。

理解以上a). ~ g). 的getopt_long()設計原則之後,我們就可以執行一個較為複雜的指令。就會得到一個很漂亮,完全符合我們預期的結果!
[root@localhost ~]# 
[root@localhost ~]# ./main --author --force 1234 --add 5678 --append --all 9012 --file -X 3456 -Y -x -y 7890 --ask 1234 --oops 5678 -Q 9012 -r 3456
You got a long option argv[1]: "--author". 

You got a long option argv[2]: "--force", but DOESN'T need argument argv[3]: "1234". 

You got a long option argv[4]: "--add" with an argument: argv[5]: "5678" 

The long option argv[6]: "--append" need an argument!! 

You got a long option argv[7]: "--all" with an argument: argv[8]: "9012". 

You got a long option argv[9]: "--file". 

You got a short option argv[10]: "-X", but DOESN'T need argument argv[11]: 3456 

You got a short option argv[12]: "-Y". 

The short option argv[13]: "-x" need an argument!! 

You got a short option argv[14]: "-y" with an argument: argv[15]: "7890" 

./main: unrecognized option '--ask'
Unknown long option argv[16]: --ask 
// usage()函式內容省略!
./main: unrecognized option '--oops'
Unknown long option argv[18]: --oops 
// usage()函式內容省略!
./main: invalid option -- 'Q'
Unknown short option argv[20]: -Q 
// usage()函式內容省略!
./main: invalid option -- 'r'
Unknown short option argv[22]: -r 
// usage()函式內容省略!
[root@localhost ~]# 
[root@localhost ~]# 
(To be continue .... )

沒有留言:

張貼留言