-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathREADME.html
More file actions
1010 lines (777 loc) · 56 KB
/
README.html
File metadata and controls
1010 lines (777 loc) · 56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<p><title>PCUnit - Portable C Unit Testing Framework</title></p>
<h1>PCUnit - Portable C Unit Testing Framework</h1>
<h2>概要</h2>
<p>PCUnitはC言語/C++言語でテスト駆動開発(Test-Driven Development; TDD)や単体テストをするための
ポータブルでコンパクトなユニットテストフレームワークです。</p>
<p>PCUnitは以下のような特長があります。</p>
<ul>
<li><p>機能</p>
<ul>
<li><a href="http://cunit.sourceforge.net/">CUnit</a>ライクなアサートマクロをサポートします。</li>
<li>アサートマクロで失敗した内容を表示できます。さらにprintf形式で追加メッセージを表示できます。</li>
<li>テストフィクスチャ(setup, teardown, initialize, cleanup)をサポートします。</li>
<li>1つのテストを繰り返し行うRepeatedTestをサポートします。これを利用して、データ駆動テストを行うこともできます。</li>
<li>ディスプレイやキーボードがないターゲット上でテストするために、ユーザー定義の入出力関数を設定できます。</li>
<li>実行するテストをインタラクティブに選択できるコンソールモードをサポートします。</li>
<li>ターミナルが対応していればテスト結果のカラー表示ができます。</li>
<li>テスト関数の雛形生成や自動登録ができます。</li>
<li>テスト結果をXMLファイルで出力することができます。</li>
<li>モックオブジェクトを使用することができます。</li>
</ul></li>
<li><p>移植性</p>
<ul>
<li>プラットフォーム非依存な実装なので、大抵のPC向けまたは組み込み向けのC/C++コンパイラでビルドすることができます。
つまり、ホスト環境とターゲット環境の両方で動作する共通のテストコードを実装することができます。</li>
<li>たとえ標準Cライブラリが使えない環境でも使用可能です。</li>
</ul></li>
</ul>
<h2>リポジトリ</h2>
<ul>
<li><a href="https://github.com/katono/PCUnit">https://github.com/katono/PCUnit</a></li>
<li><a href="https://bitbucket.org/katono/pcunit">https://bitbucket.org/katono/pcunit</a></li>
</ul>
<h2>ビルド方法</h2>
<p>GNU開発環境の場合は、PCUnitディレクトリでmakeを実行してください。makeを実行するとlibpcunit.aが生成されるので
それをテストプロジェクトに静的リンクしてください。デフォルトのコンパイラはgccですが、
適宜Makefileを修正してターゲット用のクロスコンパイラやコンパイラオプションを指定してください。
ホスト環境にインストールしたい場合は、make installを実行してください。
make installを実行すると/usr/local/libにlibpcunit.aを、/usr/local/include/PCUnitにヘッダファイルを、
/usr/local/binにユーティリティをインストールします。
make uninstallを実行するとアンインストールします。
インストール先ディレクトリを/usr/localから変更してインストールする場合は、
make install INSTALLDIR=/foo/barのようにINSTALLDIRに任意のインストール先ディレクトリを指定してください。
同様にアンインストールする場合は、make uninstall INSTALLDIR=/foo/barを実行してください。</p>
<p>GNU開発環境でない場合は、PCUnitディレクトリ以下のソースファイルとヘッダファイルをテストプロジェクトに追加して
テストコードと共にビルドしてください。あるいはPCUnitの静的ライブラリをビルドするプロジェクトを作成し、
ビルドしたライブラリをテストプロジェクトに静的リンクしてください。</p>
<h3>ビルド設定</h3>
<p>PCUnitはコンパイラオプションのマクロ定義で以下の設定をすることができます。
PCUnitのビルドが失敗する場合は、適宜<code>PCU_NO_*</code>マクロを定義することでビルド可能になります。
ただし、PCUnitをビルドするためには最低限<code><stddef.h></code>と<code><limits.h></code>が必要です。</p>
<ul>
<li>vsprintfが使用できないためにビルドが失敗する場合は、<code>PCU_NO_VSPRINTF</code>マクロを定義してください。</li>
<li>setjmp/longjmpが使用できないためにビルドが失敗する場合は、<code>PCU_NO_SETJMP</code>マクロを定義してください。</li>
<li><code><string.h></code>と<code><stdlib.h></code>の関数が使用できないためにビルドが失敗する場合は、
<code>PCU_NO_LIBC</code>マクロを定義してください。
このマクロを定義した場合は<code>PCU_NO_VSPRINTF</code>、<code>PCU_NO_SETJMP</code>を定義する必要はありません。</li>
<li><code><stdarg.h></code>がないためにビルドが失敗する場合は、<code>PCU_NO_STDARG</code>マクロを定義してください。</li>
<li>プロセッサにFPUがなく、ソフトウェア浮動小数点ライブラリも使用できないためにビルドが失敗する場合は、
<code>PCU_NO_FLOATINGPOINT</code>マクロを定義してください。</li>
<li>32ビットの除算ができないためにビルドが失敗する(例えばgccで<code>___divsi3</code>などのリンクエラーが発生する)場合は、
<code>PCU_NO_DIV32</code>マクロを定義してください。</li>
<li>コンソールモードが不要な場合は、<code>PCU_NO_CONSOLE_RUN</code>マクロを定義してください。
<code>PCU_console_run</code>が使用できなくなりますが、コードサイズが少し小さくなります。</li>
<li>ワイド文字列をチェックするアサートマクロを使用したい場合は、<code>PCU_USE_WCHAR</code>マクロを定義してください。
<code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義済みならば、<code>PCU_USE_WCHAR</code>マクロは自動的に定義済みになります。</li>
<li><code>PCU_format</code>/<code>PCU_formatW</code>で使用する静的領域のサイズを変更したい場合は、
<code>PCU_FORMAT_BUFSIZE</code>マクロの値を定義してください。</li>
</ul>
<h2>テスト構成</h2>
<p>PCUnitのテストはこのような構成になっています。</p>
<ul>
<li>テスト実行関数
<ul>
<li>スイートメソッド 1
<ul>
<li>テストスイート 1
<ul>
<li>テストケース 1-1</li>
<li>テストケース 1-2</li>
<li>・・・</li>
</ul></li>
</ul></li>
<li>スイートメソッド 2
<ul>
<li>テストスイート 2
<ul>
<li>テストケース 2-1</li>
<li>テストケース 2-2</li>
<li>・・・</li>
</ul></li>
</ul></li>
<li>スイートメソッド 3
<ul>
<li>テストスイート 3
<ul>
<li>テストケース 3-1</li>
<li>テストケース 3-2</li>
<li>・・・</li>
</ul></li>
</ul></li>
<li>・・・</li>
</ul></li>
</ul>
<h3>テストケース</h3>
<p><em>テストケース</em> は1つのテスト関数を実行するためのデータ構造です。
テストケースは<code>PCU_Test</code>という構造体で次のように型定義されています。</p>
<pre><code>typedef struct {
const char *name; /* テストケース名 */
void (*test)(void); /* テスト関数 */
int ntimes; /* テスト関数を実行する回数 */
... /* 以下、非公開メンバ */
} PCU_Test;
</code></pre>
<p>ntimesによる繰り返しはsetup, teardownの実行も含みます。
ntimesが0の場合は1を指定したと見なします。また、負の数ならばそのテストケースはスキップされます。</p>
<h3>テストスイート</h3>
<p><em>テストスイート</em> は複数のテストケースを管理するためのデータ構造です。
テストスイートは<code>PCU_Suite</code>という構造体で次のように型定義されています。</p>
<pre><code>typedef struct {
const char *name; /* テストスイート名 */
PCU_Test *tests; /* テストケースの配列 */
int ntests; /* testsの要素数 */
int (*setup)(void); /* testsの各テスト関数の実行前に呼ばれる関数 */
int (*teardown)(void); /* testsの各テスト関数の実行後に呼ばれる関数 */
int (*initialize)(void); /* testsの最初のテストの実行前に呼ばれる関数 */
int (*cleanup)(void); /* testsの最後のテストの実行後に呼ばれる関数 */
... /* 以下、非公開メンバ */
} PCU_Suite;
</code></pre>
<p>setupとteardownの戻り値は、0ならば正常、非0ならば異常です。
setupが異常の場合、テスト関数とteardownは実行されません。</p>
<p>initializeとcleanupの戻り値は、0ならば正常、非0ならば異常です。
initializeが異常の場合、testsの全てのテストとcleanupは実行されません。</p>
<p>setup, teardown, initialize, cleanupは、0が指定された場合は呼ばれません。</p>
<h3>スイートメソッド</h3>
<p><em>スイートメソッド</em> はテスト実行関数からテストスイートにアクセスするためのインターフェイスです。
スイートメソッドの詳細については後述します。</p>
<h2>簡単な使い方</h2>
<h3>テスト対象関数</h3>
<p>簡単な例として、add関数とsub関数をテスト対象関数とします。</p>
<p>add関数は引数aと引数bを足した値を返し、sub関数は引数aから引数bを引いた値を返す関数です。
プロトタイプ宣言をしたヘッダファイルAddSub.hを作成します。</p>
<pre><code>[AddSub.h]
1 #ifndef ADDSUB_H_INCLUDED
2 #define ADDSUB_H_INCLUDED
3 int add(int a, int b);
4 int sub(int a, int b);
5 #endif
</code></pre>
<h3>テスト関数</h3>
<p>add関数とsub関数を実装する前に、テスト関数を先に実装します。
テスト関数を実装するソースファイル名は任意ですが、テスト対象のソースファイル名にTestを付けた名前にするとよいでしょう。
次のように実装します。</p>
<pre><code>[AddSubTest.c]
1 #include "PCUnit/PCUnit.h"
2 #include "AddSub.h"
3
4 static void test_add(void)
5 {
6 PCU_ASSERT_EQUAL(3, add(2, 1));
7 PCU_ASSERT_EQUAL(0, add(0, 0));
8 PCU_ASSERT_EQUAL(1, add(-1, 2));
9 }
10
11 static void test_sub(void)
12 {
13 PCU_ASSERT_EQUAL(1, sub(2, 1));
14 PCU_ASSERT_EQUAL(0, sub(0, 0));
15 PCU_ASSERT_EQUAL(-3, sub(-1, 2));
16 }
17
</code></pre>
<p>PCUnitを使うためには<code>PCUnit.h</code>をインクルードする必要があります。
<code>PCUnit.h</code>のインクルードパスは適宜テストプロジェクトで指定してください。</p>
<p>テスト関数は引数・戻り値が共にvoidの関数です。テスト関数名は任意ですが、testを付けた名前にするとよいでしょう。
他のソースファイルから呼び出さないならばstatic関数にしてください。</p>
<p>ここでは<code>PCU_ASSERT_EQUAL</code>マクロを使用してテスト対象関数の戻り値が仕様どおりかチェックしています。
<code>PCU_ASSERT_EQUAL</code>マクロの2つの引数が等しければOKで、異なっていたらテスト失敗です。
最初の引数に予測される値を指定し、2番目の引数に実際の値を指定します。</p>
<h3>スイートメソッド</h3>
<p>次に、スイートメソッドを定義します。
スイートメソッドは <em>static</em> な<code>PCU_Suite</code>の変数へのポインタを返すグローバル関数です。
スイートメソッドは<code>PCU_Suite</code>のメンバのtestsやsetup関数等のスコープを小さくする役割を果たします。
関数名は任意ですが、<code>テストスイート名_suite()</code>と付けるとよいでしょう。
次のように定義します。</p>
<pre><code>[AddSubTest.c]
18 PCU_Suite *AddSubTest_suite(void)
19 {
20 static PCU_Test tests[] = {
21 { "test_add", test_add },
22 { "test_sub", test_sub },
23 };
24 static PCU_Suite suite = { "AddSubTest", tests, sizeof tests / sizeof tests[0] };
25 return &suite;
26 }
</code></pre>
<p>スイートメソッドは引数がvoid、戻り値が<code>PCU_Suite *</code>の関数です。</p>
<p>スイートメソッドではまず、<code>PCU_Test</code>構造体の配列testsを <em>static</em> で定義と同時に初期化します。
<code>PCU_Test</code>構造体の最初のメンバnameには任意のテストケース名を指定します。
2番目のメンバtestには先に定義したテスト関数を指定します。
3番目のメンバはntimesですが、この例では省略されているので0で初期化され、テスト関数は1回実行されます。
繰り返しが必要な場合はntimesに回数を指定してください。
後で新しいテストケースを追加したい場合は、新しいテスト関数を定義してこの配列の初期化に追加してください。
(<code>pcunit_register.rb</code>ユーティリティを使用すればテストケース登録を自動化できます。)</p>
<p>次に、<code>PCU_Suite</code>構造体の変数suiteを <em>static</em> で定義と同時に初期化します。
<code>PCU_Suite</code>構造体の最初のメンバnameには任意のテストスイート名を指定します。
2番目のメンバtestsには<code>PCU_Test</code>の配列testsを指定します。
3番目のメンバntestsにはtestsの要素数を指定します。
4番目以下のメンバsetup, teardown, initialize, cleanupはこの例では省略されているのでそれぞれ0で初期化されます。
setup, teardown, initialize, cleanupが必要な場合はそれぞれの関数を定義し指定してください。</p>
<p>この関数の最後でsuiteのアドレスを返します。</p>
<h3>main関数</h3>
<p>main関数は次のように定義します。</p>
<pre><code>[main.c]
1 #include "PCUnit/PCUnit.h"
2 #include <stdio.h> /* for putchar */
3
4 PCU_Suite *AddSubTest_suite(void);
5
6 int main(void)
7 {
8 const PCU_SuiteMethod suites[] = {
9 AddSubTest_suite,
10 };
11 PCU_set_putchar(putchar);
12 return PCU_run(suites, sizeof suites / sizeof suites[0]);
13 }
</code></pre>
<p>main関数がテストを実装したソースと別ファイルの場合はスイートメソッドのプロトタイプ宣言をしてください。</p>
<p>main関数ではまず、<code>PCU_SuiteMethod</code>型の配列を宣言します。
<code>PCU_SuiteMethod</code>型はスイートメソッドへのポインタ型で、次のように型定義されています。</p>
<pre><code>typedef PCU_Suite *(*PCU_SuiteMethod)(void);
</code></pre>
<p>ここでは<code>AddSubTest_suite</code>だけで初期化しています。
後で新しいテストスイートを追加したい場合は、新しいテストスイートに対応するスイートメソッドをこの配列の初期化に追加してください。
(<code>pcunit_register.rb</code>ユーティリティを使用すればスイートメソッド登録を自動化できます。)</p>
<p>次に、<code>PCU_set_putchar</code>関数でテスト結果の出力関数をputcharに設定しています。
この関数ではユーザー定義のputchar相当の関数を用意することでテスト結果の出力先を変更することができます。
例えばターゲット上で動作させる時はシリアル出力関数などを指定するとよいでしょう。</p>
<p>最後に、テスト実行関数である<code>PCU_run</code>関数を呼び出します。
<code>PCU_run</code>の最初の引数は<code>PCU_SuiteMethod</code>型の配列で、2番目の引数はその配列の要素数です。
<code>PCU_run</code>の戻り値は、失敗がなければ0、1つでも失敗があれば非0です。</p>
<p>これでテストコードの準備は整いました。</p>
<h3>ビルド、実行、修正の繰り返し</h3>
<p>ビルドするとadd関数とsub関数の実装がないため、リンクエラーになります。</p>
<p>ここで、AddSub.cを作成し、add関数とsub関数の実装をします。</p>
<pre><code>[AddSub.c]
1 #include "AddSub.h"
2 int add(int a, int b) { return 0; }
3 int sub(int a, int b) { return 0; }
</code></pre>
<p>単純な関数ですが、わざとテストに失敗させるために0を返すようにしておきます。</p>
<p>再度ビルドして実行すると、テストに失敗します。
このように出力されます。</p>
<pre><code>Suite: AddSubTest
Test: test_add
AddSubTest.c:6: PCU_ASSERT_EQUAL(3, add(2, 1))
expected : 0x00000003 (3)
actual : 0x00000000 (0)
Test: test_sub
AddSubTest.c:13: PCU_ASSERT_EQUAL(1, sub(2, 1))
expected : 0x00000001 (1)
actual : 0x00000000 (0)
2 Tests, 2 Failures, 0 Skipped
</code></pre>
<p>失敗したテストスイート名、テストケース名、ファイル名、行番号、アサートマクロ、アサートマクロの引数の値が表示されます。
その後、そのテストスイートに登録されている全テストケース数、実行して失敗したテストケース数、
スキップされたテストケース数が表示されます。</p>
<p>テストにパスするために、add関数とsub関数を修正します。</p>
<pre><code>[AddSub.c]
- int add(int a, int b) { return 0; }
- int sub(int a, int b) { return 0; }
+ int add(int a, int b) { return a + b; }
+ int sub(int a, int b) { return a - b; }
</code></pre>
<p>修正したらビルドして実行します。
このように出力されます。</p>
<pre><code>Suite: AddSubTest
2 Tests, 0 Failures, 0 Skipped
OK
</code></pre>
<p>全てのテストにパスすると、OKのメッセージが表示されます。
<code>PCU_set_verbose</code>で出力が冗長モードになっていなければ、パスしたテストケースの情報は表示されません。</p>
<p>OKのメッセージは1つのテストスイートにつき1つ表示されます。
この例ではテストスイートは1つでしたが、テストスイートが複数の場合、
全てのテストスイートにOKが表示されるまで修正を繰り返してください。</p>
<h2>アサートマクロ</h2>
<p>アサートマクロはテスト関数内で使用可能です。
各アサートマクロの引数は2回以上評価されないので、マクロ展開による副作用を気にする必要はありません。</p>
<p>アサーション失敗時はlongjmpによってテスト関数から抜けます。
ただし、PCUnitが<code>PCU_NO_SETJMP</code>マクロまたは<code>PCU_NO_LIBC</code>マクロが定義済みでビルドされている場合は、
longjmpの代わりにreturnによってテスト関数から抜けます。
この場合、スタブ等のテスト関数内で呼び出される関数から一気に抜けることはできなくなります。</p>
<p>以下にPCUnitが提供するアサートマクロを示します。</p>
<ul>
<li><p><strong><code>PCU_ASSERT(expr)</code></strong></p>
<p>任意の式exprが真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_TRUE(expr)</code></strong></p>
<p>任意の式exprが真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_FALSE(expr)</code></strong></p>
<p>任意の式exprが偽かどうかチェックします。
真ならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_EQUAL(expected, actual)</code></strong></p>
<p>expectedとactualが整数である前提で、expectedとactualが等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_NOT_EQUAL(value1, value2)</code></strong></p>
<p>value1とvalue2が整数である前提で、value1とvalue2が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_PTR_EQUAL(expected, actual)</code></strong></p>
<p>expectedとactualがポインタである前提で、expectedとactualのポインタの値が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_PTR_NOT_EQUAL(value1, value2)</code></strong></p>
<p>value1とvalue2がポインタである前提で、value1とvalue2のポインタの値が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_PTR_NULL(value)</code></strong></p>
<p>valueがポインタである前提で、valueがNULLかどうかチェックします。
NULLでないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_PTR_NOT_NULL(value)</code></strong></p>
<p>valueがポインタである前提で、valueがNULLでないかどうかチェックします。
NULLならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_STRING_EQUAL(expected, actual)</code></strong></p>
<p>expectedとactualが文字列(const char *)である前提で、expectedとactualの文字列が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_STRING_NOT_EQUAL(value1, value2)</code></strong></p>
<p>value1とvalue2が文字列(const char *)である前提で、value1とvalue2の文字列が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRING_EQUAL(expected, actual, n)</code></strong></p>
<p>expectedとactualが文字列(const char *)である前提で、expectedとactualの文字列の先頭からn文字が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRING_NOT_EQUAL(value1, value2, n)</code></strong></p>
<p>value1とvalue2が文字列(const char *)である前提で、value1とvalue2の文字列の先頭からn文字が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_STRINGW_EQUAL(expected, actual)</code></strong></p>
<p>expectedとactualがワイド文字列(const wchar_t *)である前提で、expectedとactualのワイド文字列が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。
失敗時の引数の文字列表示は、現在のロケールの<code>LC_CTYPE</code>カテゴリに依存します。
なお、このマクロを使用するためにはPCUnitが<code>PCU_USE_WCHAR</code>マクロが定義済みでビルドされている必要があります。</p></li>
<li><p><strong><code>PCU_ASSERT_STRINGW_NOT_EQUAL(value1, value2)</code></strong></p>
<p>value1とvalue2がワイド文字列(const wchar_t *)である前提で、value1とvalue2のワイド文字列が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。
失敗時の引数の文字列表示は、現在のロケールの<code>LC_CTYPE</code>カテゴリに依存します。
なお、このマクロを使用するためにはPCUnitが<code>PCU_USE_WCHAR</code>マクロが定義済みでビルドされている必要があります。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRINGW_EQUAL(expected, actual, n)</code></strong></p>
<p>expectedとactualがワイド文字列(const wchar_t *)である前提で、expectedとactualのワイド文字列の先頭からn文字が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。
失敗時の引数の文字列表示は、現在のロケールの<code>LC_CTYPE</code>カテゴリに依存します。
なお、このマクロを使用するためにはPCUnitが<code>PCU_USE_WCHAR</code>マクロが定義済みでビルドされている必要があります。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRINGW_NOT_EQUAL(value1, value2, n)</code></strong></p>
<p>value1とvalue2がワイド文字列(const wchar_t *)である前提で、value1とvalue2のワイド文字列の先頭からn文字が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。
失敗時の引数の文字列表示は、現在のロケールの<code>LC_CTYPE</code>カテゴリに依存します。
なお、このマクロを使用するためにはPCUnitが<code>PCU_USE_WCHAR</code>マクロが定義済みでビルドされている必要があります。</p></li>
<li><p><strong><code>PCU_ASSERT_STRINGT_EQUAL(expected, actual)</code></strong></p>
<p><code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義されている場合は<code>PCU_ASSERT_STRINGW_EQUAL</code>に展開され、
そうでない場合は<code>PCU_ASSERT_STRING_EQUAL</code>に展開されます。</p></li>
<li><p><strong><code>PCU_ASSERT_STRINGT_NOT_EQUAL(value1, value2)</code></strong></p>
<p><code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義されている場合は<code>PCU_ASSERT_STRINGW_NOT_EQUAL</code>に展開され、
そうでない場合は<code>PCU_ASSERT_STRING_NOT_EQUAL</code>に展開されます。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRINGT_EQUAL(expected, actual, n)</code></strong></p>
<p><code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義されている場合は<code>PCU_ASSERT_NSTRINGW_EQUAL</code>に展開され、
そうでない場合は<code>PCU_ASSERT_NSTRING_EQUAL</code>に展開されます。</p></li>
<li><p><strong><code>PCU_ASSERT_NSTRINGT_NOT_EQUAL(value1, value2, n)</code></strong></p>
<p><code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義されている場合は<code>PCU_ASSERT_NSTRINGW_NOT_EQUAL</code>に展開され、
そうでない場合は<code>PCU_ASSERT_NSTRING_NOT_EQUAL</code>に展開されます。</p></li>
<li><p><strong><code>PCU_ASSERT_MEMORY_EQUAL(expected, actual, size, n)</code></strong></p>
<p>expectedとactualがsizeバイトの型のポインタである前提で、expectedとactualの先頭からn個が等しいかどうかチェックします。
等しくないならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_MEMORY_NOT_EQUAL(value1, value2, size, n)</code></strong></p>
<p>value1とvalue2がsizeバイトの型のポインタである前提で、value1とvalue2の先頭からn個が等しくないかどうかチェックします。
等しいならば失敗を出力し、テスト関数から抜けます。</p></li>
<li><p><strong><code>PCU_ASSERT_DOUBLE_EQUAL(value1, value2, delta)</code></strong></p>
<p>value1とvalue2とdeltaが浮動小数点数である前提で、|value1 - value2| <= |delta|が真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。
なお、PCUnitが<code>PCU_NO_FLOATINGPOINT</code>マクロが定義済みでビルドされている場合は使用できません。</p></li>
<li><p><strong><code>PCU_ASSERT_DOUBLE_NOT_EQUAL(value1, value2, delta)</code></strong></p>
<p>value1とvalue2とdeltaが浮動小数点数である前提で、|value1 - value2| > |delta|が真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。
なお、PCUnitが<code>PCU_NO_FLOATINGPOINT</code>マクロが定義済みでビルドされている場合は使用できません。</p></li>
<li><p><strong><code>PCU_ASSERT_OPERATOR(value1, op, value2)</code></strong></p>
<p>value1とvalue2が符号無し整数を返す任意の式でopが代入以外の任意の二項演算子である前提で、((value1) op (value2)) が真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_OPERATOR(x < 0, ||, 100 <= x);</code> xが0未満または100以上かチェック</li>
<li><code>PCU_ASSERT_OPERATOR(x, &, 0x01);</code> xの最下位ビットが立っているかチェック</li>
</ul></li>
<li><p><strong><code>PCU_ASSERT_OPERATOR_INT(value1, op, value2)</code></strong></p>
<p>value1とvalue2が符号付き整数を返す任意の式でopが代入以外の任意の二項演算子である前提で、((value1) op (value2)) が真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_OPERATOR_INT(x, <, -1);</code> xが-1より小さい値かチェック</li>
</ul></li>
<li><p><strong><code>PCU_ASSERT_OPERATOR_DOUBLE(value1, op, value2)</code></strong></p>
<p>value1とvalue2が浮動小数点数を返す任意の式でopが比較演算子である前提で、((value1) op (value2)) が真かどうかチェックします。
偽ならば失敗を出力し、テスト関数から抜けます。
なお、PCUnitが<code>PCU_NO_FLOATINGPOINT</code>マクロが定義済みでビルドされている場合は使用できません。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_OPERATOR_DOUBLE(x, >=, 1.0);</code> xが1.0以上の値かチェック</li>
</ul></li>
<li><p><strong><code>PCU_ASSERT*_MESSAGE(*, msg)</code></strong></p>
<p>上記の各アサートマクロには、最後の引数にmsgを追加した、マクロ名の末尾に<code>_MESSAGE</code>が付いたバージョンがあります。
アサーション失敗時にmsgで指定したメッセージを追加表示できること以外は各アサートマクロと同じです。
msgの型は<code>const char *</code>です。
なお、<code>PCU_format</code>/<code>PCU_formatW</code>を使用すればprintf/wprintfと同じ形式の文字列を指定することができます。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_MESSAGE(x, "x is false");</code></li>
<li><code>PCU_ASSERT_EQUAL_MESSAGE(x, y, PCU_format("a:%s, b:%x, c:%d", a, b, c));</code></li>
</ul></li>
<li><p><strong><code>PCU_FAIL(msg)</code></strong></p>
<p>無条件に失敗を出力し、テスト関数から抜けます。
失敗表示の際にmsgで指定したメッセージを表示します。
msgの型は<code>const char *</code>です。
なお、<code>PCU_format</code>/<code>PCU_formatW</code>を使用すればprintf/wprintfと同じ形式の文字列を指定することができます。</p></li>
<li><p><strong><code>PCU_MESSAGE(msg)</code></strong></p>
<p>合否チェックを行わず、msgで指定したメッセージを表示します。
このマクロはテスト関数から抜けません。
msgの型は<code>const char *</code>です。
なお、<code>PCU_format</code>/<code>PCU_formatW</code>を使用すればprintf/wprintfと同じ形式の文字列を指定することができます。</p></li>
</ul>
<h2>API</h2>
<ul>
<li><p><strong><code>int PCU_run(const PCU_SuiteMethod *suite_methods, int num)</code></strong></p>
<p><code>PCU_SuiteMethod</code>の配列<code>suite_methods</code>から導かれる全テストを実行します。
<code>num</code>には<code>suite_methods</code>の要素数を指定します。
全テストを実行した結果、失敗がなければ0を、1つでも失敗があれば非0を返します。</p></li>
<li><p><strong><code>int PCU_console_run(const PCU_SuiteMethod *suite_methods, int num)</code></strong></p>
<p>コンソールモードでテストを実行します。
実行するテストを対話的に選択したい場合、<code>PCU_run</code>の代わりにこちらを使います。
引数は<code>PCU_run</code>と同じです。
テストを実行した結果、失敗がなければ0を、1つでも失敗があれば非0を返します。
なお、PCUnitが<code>PCU_NO_CONSOLE_RUN</code>マクロが定義済みでビルドされている場合は使用できません。</p></li>
<li><p><strong><code>void PCU_set_putchar(PCU_Putchar func)</code></strong></p>
<p>1文字出力する関数を設定します。
<code>PCU_Putchar</code>型はputcharと同じ型の関数へのポインタ型で、<code>typedef int (*PCU_Putchar)(int);</code>と型定義されています。
<code>PCU_run</code>または<code>PCU_console_run</code>の前に必ず設定してください。</p></li>
<li><p><strong><code>void PCU_set_getchar(PCU_Getchar func)</code></strong></p>
<p>入力した1文字を取得する関数を設定します。
<code>PCU_Getchar</code>型はgetcharと同じ型の関数へのポインタ型で、<code>typedef int (*PCU_Getchar)(void);</code>と型定義されています。
<code>PCU_console_run</code>の前に必ず設定してください。</p></li>
<li><p><strong><code>void PCU_set_verbose(int verbose_flag)</code></strong></p>
<p><code>verbose_flag</code>が非0なら、パスしたテストやスキップしたテストもテスト結果に出力する冗長モードに移行します。
<code>verbose_flag</code>が0なら、出力を通常モードに戻します。</p></li>
<li><p><strong><code>void PCU_enable_color(void)</code></strong></p>
<p>ターミナルがカラー表示に対応していれば、テスト結果のカラー表示を有効にします。</p></li>
<li><p><strong><code>void PCU_disable_color(void)</code></strong></p>
<p>テスト結果のカラー表示を無効にします。</p></li>
<li><p><strong><code>const char *PCU_suite_name(void)</code></strong></p>
<p>現在実行中のテストスイート名を返します。
テスト関数、setup関数、teardown関数、initialize関数、cleanup関数内で使用可能です。</p></li>
<li><p><strong><code>const char *PCU_test_name(void)</code></strong></p>
<p>現在実行中のテストケース名を返します。
テスト関数、setup関数、teardown関数内で使用可能です。</p></li>
<li><p><strong><code>int PCU_repeat_counter(void)</code></strong></p>
<p>テストケースの実行が、現在何回目(0オリジン)であるかを返します。</p>
<ul>
<li><code>PCU_Test</code>のntimesが0の場合は常に0を返します。</li>
<li>ntimesが0より大きい場合は0 ~ ntimes - 1の値を返します。</li>
</ul>
<p>テスト関数、setup関数、teardown関数内で使用可能です。</p>
<p>例えば、データ駆動テストにおけるテストデータのテーブルから要素を取得するためのインデックスに利用できます。
<code>PCU_Test</code>のntimesにはテストデータの要素数を指定してください。</p></li>
<li><p><strong><code>const char *PCU_format(const char *format, ...)</code></strong></p>
<p>引数に指定したprintf形式の文字列を静的領域に展開し、その領域のポインタを返します。
<code>PCU_ASSERT*_MESSAGE</code>、<code>PCU_FAIL</code>、<code>PCU_MESSAGE</code>のメッセージをprintf形式にしたい場合に利用できます。
静的領域のサイズはPCUnitのビルド時に<code>PCU_FORMAT_BUFSIZE</code>マクロの値で定義できます。定義しない場合のデフォルト値は512です。
内部でvsprintfを使用しているので文字列展開後のサイズが<code>PCU_FORMAT_BUFSIZE</code>を超えないように注意してください。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_EQUAL_MESSAGE(x, y, PCU_format("a:%s, b:%x, c:%d", a, b, c));</code></li>
</ul>
<p>なお、PCUnitが<code>PCU_NO_STDARG</code>マクロが定義済みでビルドされている場合は使用できません。
<code>PCU_NO_STDARG</code>マクロが定義済みの場合は、代わりに<code>PCU_format0</code>~<code>PCU_format9</code>(0~9は引数<code>format</code>より後の引数の個数)を使用してください。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_EQUAL_MESSAGE(x, y, PCU_format3("a:%s, b:%x, c:%d", a, b, c));</code></li>
</ul></li>
<li><p><strong><code>const char *PCU_formatW(const wchar_t *format, ...)</code></strong></p>
<p>引数に指定したwprintf形式のワイド文字列をマルチバイト文字列に変換して静的領域に展開し、その領域のポインタを返します。
<code>PCU_ASSERT*_MESSAGE</code>、<code>PCU_FAIL</code>、<code>PCU_MESSAGE</code>のメッセージをwprintf形式にしたい場合に利用できます。
静的領域のサイズはPCUnitのビルド時に<code>PCU_FORMAT_BUFSIZE</code>マクロの値で定義できます。定義しない場合のデフォルト値は512です。
内部でvsprintfを使用しているので文字列展開後のサイズが<code>PCU_FORMAT_BUFSIZE</code>を超えないように注意してください。
なお、この関数を使用するためにはPCUnitが<code>PCU_USE_WCHAR</code>マクロが定義済みでビルドされている必要があります。</p>
<p>例:</p>
<ul>
<li><code>PCU_ASSERT_EQUAL_MESSAGE(x, y, PCU_formatW(L"a:%s, b:%x, c:%d", a, b, c));</code></li>
</ul></li>
<li><p><strong><code>const char *PCU_formatT(const TCHAR *format, ...)</code></strong></p>
<p><code>PCU_formatT</code>はマクロです。
<code>_UNICODE</code>マクロまたは<code>UNICODE</code>マクロが定義されている場合は<code>PCU_formatW</code>に展開され、
そうでない場合は<code>PCU_format</code>に展開されます。</p></li>
</ul>
<h2>ヘルパーマクロ</h2>
<p><code>PCU_Test</code>の配列初期化の際に、テストケース名とテスト関数を同じ名前にする場合、ヘルパーマクロが利用できます。
ヘルパーマクロは次のように定義されています。</p>
<pre><code>#define PCU_TEST(func) { #func, func }
#define PCU_TEST_REPEATED(func, ntimes) { #func, func, ntimes }
#define PCU_TEST_SKIPPED(func) { #func, func, -1 }
</code></pre>
<h3>例</h3>
<pre><code>static PCU_Test tests[] = {
PCU_TEST(test_hoge), /* test_hoge関数を登録 */
PCU_TEST(test_piyo), /* test_piyo関数を登録 */
PCU_TEST_REPEATED(test_foo, 5), /* test_foo関数を登録(5回実行) */
PCU_TEST_SKIPPED(test_bar), /* test_bar関数を登録(スキップ) */
};
</code></pre>
<h2>ユーティリティ</h2>
<h3><code>pcunit_template.rb</code></h3>
<p><code>pcunit_template.rb</code>はPCUnit用のソースファイルの雛形を生成するRubyスクリプトです。
書式は次の通りです。</p>
<pre><code>pcunit_template.rb [suite_name ...] [-d DIR] [-p [EXT]] [-m [FILE]] [-M [FILE] [-i]] [-o]
</code></pre>
<p><code>suite_name</code>に1つ以上のテストスイート名を指定すると、<code>テストスイート名.c</code>というファイルを生成します。
生成されたファイルにはあらかじめ<code>テストスイート名_suite()</code>という名前のスイートメソッドや、
setup関数・テスト関数等の雛形が定義されています。
適宜このファイルを編集して使用してください。
また、main関数やMakefileの雛形を生成することもできます。</p>
<h4>オプション</h4>
<ul>
<li><p><code>-d DIR</code></p>
<p><code>DIR</code>にファイルを生成するディレクトリを指定してください。
このオプションを省略した場合、カレントディレクトリを指定したと見なします。</p></li>
<li><p><code>-p [EXT]</code></p>
<p>生成するファイルをC++にします。
<code>EXT</code>にC++の拡張子(cpp, cc, cxx等)を指定してください。<code>EXT</code>を省略した場合、拡張子はcppになります。</p></li>
<li><p><code>-m [FILE]</code></p>
<p><code>PCU_run</code>を呼び出すmain関数を定義したファイルを生成します。
<code>FILE</code>にファイル名を指定してください。
<code>FILE</code>を省略した場合、ファイル名は<code>main.c</code>(<code>-p</code>指定の場合は<code>main.cpp</code>)になります。</p></li>
<li><p><code>-M [FILE] [-i]</code></p>
<p>テストプロジェクトのMakefileの雛型を生成します。
<code>FILE</code>にファイル名を指定してください。
<code>FILE</code>を省略した場合、ファイル名は<code>Makefile</code>になります。
<code>-i</code>を指定した場合、libpcunit.aが既にインストールされている前提のMakefileを生成します。
<code>-i</code>を省略した場合、テストコードとPCUnitを共にビルドするMakefileを生成します。</p></li>
<li><p><code>-o</code></p>
<p>生成するファイルと同じ名前のファイルが既に存在している場合でも上書きします。</p></li>
</ul>
<h3><code>pcunit_register.rb</code></h3>
<p><code>pcunit_register.rb</code>はテスト関数を自動登録するRubyスクリプトです。
書式は次の通りです。</p>
<pre><code>pcunit_register.rb [-d DIR] [-e PATTERN] [-n]
</code></pre>
<p><code>pcunit_register.rb</code>は、あるディレクトリ以下の全てのソースファイルを再帰的に検索し、
<code>test</code>で始まるテスト関数の中で、<code>PCU_Test</code>のstatic配列の初期化に登録されていない関数を自動的に登録します。
また、<code>PCU_run</code>の引数になる<code>PCU_SuiteMethod</code>の配列の初期化の登録も行います。</p>
<p>ソースファイルを更新するので、更新前のファイルはファイル名に<code>.bak</code>を付けてバックアップします。
更新する必要がないファイルには何もしません。</p>
<p><code>PCU_Test</code>の配列初期化を以下のようにしておくと、テスト関数の登録を.pcutestsファイルに追い出すことができます。.pcutestsファイルは自動的に生成されるので、手動で作成する必要はありません。</p>
<pre><code>static PCU_Test tests[] = {
#include "FooTest.pcutests"
};
</code></pre>
<p>使用するビルドツールにて、テストプロジェクトのビルド時にこのスクリプトを実行するように設定しておけば、
テスト関数を手動で登録をする必要がなくなります。
例えばMakefileならばallターゲットを次のように修正するとよいでしょう。</p>
<pre><code>- all: $(TARGET)
+ all: pcunit_register $(TARGET)
+
+ pcunit_register:
+ pcunit_register.rb
</code></pre>
<h4>オプション</h4>
<ul>
<li><p><code>-d DIR</code></p>
<p><code>DIR</code>にテストプロジェクトのソースファイルのディレクトリを指定してください。
このオプションは複数指定できます。
このオプションを省略した場合、カレントディレクトリを指定したと見なします。</p></li>
<li><p><code>-e PATTERN</code></p>
<p><code>PATTERN</code>に検索対象から除外するディレクトリ名/ファイル名の正規表現パターンを指定してください。
このオプションは複数指定できます。</p></li>
<li><p><code>-n</code></p>
<p>更新前ファイルのバックアップをしなくなります。</p></li>
</ul>
<h3><code>pcunit_xml_output.rb</code></h3>
<p><code>pcunit_xml_output.rb</code>はテスト結果をXMLファイルで出力するRubyスクリプトです。
書式は次の通りです。</p>
<pre><code>pcunit_xml_output.rb [output_file] [-e] [-n]
</code></pre>
<p><code>pcunit_xml_output.rb</code>は、テストプログラムが標準出力へ出力したテスト結果を標準入力から読み取り、XMLファイルに変換して出力します。
また、標準入力をそのまま標準出力にも出力します。
<code>output_file</code>に出力するXMLファイル名を指定します。
<code>output_file</code>を省略した場合、XMLファイル名は<code>test_results.xml</code>になります。</p>
<p>全てのテスト結果を集計したい場合は、テストプログラムの出力を<code>PCU_set_verbose</code>で冗長モードにしてください。</p>
<p>次のようにパイプを利用して、テストプログラムの標準出力を入力として使用します。</p>
<pre><code>$ ./alltests | pcunit_xml_output.rb
</code></pre>
<p>既にテキストファイルに保存したテスト結果をリダイレクトを利用して変換することもできます。</p>
<pre><code>$ pcunit_xml_output.rb < test_results.txt
</code></pre>
<h4>オプション</h4>
<ul>
<li><p><code>-e</code></p>
<p>1つでもテスト結果に失敗があれば非0を終了コードとして返すようになります。</p></li>
<li><p><code>-n</code></p>
<p>テスト結果を標準出力に出力しなくなります。</p></li>
</ul>
<h3><code>pcunit_mock.rb</code></h3>
<p><code>pcunit_mock.rb</code>はモックのソースファイルを生成するRubyスクリプトです。
書式は次の通りです。</p>
<pre><code>pcunit_mock.rb header_file ... [OPTIONS]
</code></pre>
<p><code>header_file</code>に指定したヘッダファイルでプロトタイプ宣言されているグローバル関数のモックのソースファイルを生成します。
<code>header_file</code>は複数指定またはワイルドカードが使用できます。</p>
<h4>オプション</h4>
<ul>
<li><p><code>-d DIR</code></p>
<p><code>DIR</code>にファイルを生成するディレクトリを指定してください。
このオプションを省略した場合、カレントディレクトリを指定したと見なします。</p></li>
<li><p><code>-e PATTERN</code></p>
<p><code>header_file</code>にワイルドカードで指定した場合、<code>PATTERN</code>に除外するディレクトリ名/ファイル名の正規表現パターンを指定してください。
このオプションは複数指定できます。</p></li>
<li><p><code>-s [SRC_DIR]</code></p>
<p><code>header_file</code>で宣言されているオリジナルの関数をテストで使用したい場合、関数の定義のあるソースファイルのディレクトリを<code>SRC_DIR</code>に指定してください。
<code>SRC_DIR</code>を省略した場合、<code>header_file</code>と同じディレクトリを指定したと見なします。</p></li>
<li><p><code>-p PREFIX</code></p>
<p><code>PREFIX</code>にファイルを生成するモックのソースファイルのプレフィックスを指定してください。
このオプションを省略した場合、<code>mock_</code>を指定したと見なします。</p></li>
<li><p><code>--include FILE</code></p>
<p>生成するモックに、<code>FILE</code>で指定したファイルのインクルードを追加します。
このオプションは複数指定できます。</p></li>
<li><p><code>--type-int TYPE</code> / <code>--type-float TYPE</code> / <code>--type-string TYPE</code> / <code>--type-wstring TYPE</code> / <code>--type-tstring TYPE</code> / <code>--type-ptr TYPE</code></p>
<p>これらのオプションは、それぞれ<code>TYPE</code>にユーザー定義の整数型、浮動小数点数型、文字列型、ワイド文字列型、TCHARの文字列型、ポインタ型を指定します。
プロトタイプ宣言の引数の型が、整数型等のtypedefの場合に使用してください。
これらのオプションは複数指定できます。</p></li>
<li><p><code>--others</code></p>
<p>生成するモックのソースファイルを、PCUnit以外のユニットテストフレームワークで使用できるようになります。
このオプションを使う場合は、テストコードのどこか1箇所で<code>void PCU_mock_fail(const char *msg)</code>関数を定義する必要があります。
<code>PCU_mock_fail()</code>関数では、メッセージを表示してテストを失敗するマクロ(<code>PCU_FAIL</code>に相当)を呼んでください。
また、C++のテストコードでモックを使う場合は、モックのヘッダファイルのインクルードと<code>PCU_mock_fail()</code>の定義を<code>extern "C" {}</code>で囲んでください。</p>
<p>例: CppUTestの場合</p>
<pre><code>extern "C" {
#include "mock_Foo.h"
void PCU_mock_fail(const char *msg)
{
FAIL(msg);
}
}
</code></pre>
<p>例: GoogleTestの場合</p>
<pre><code>extern "C" {
#include "mock_Foo.h"
void PCU_mock_fail(const char *msg)
{
FAIL() << msg;
}
}
</code></pre>
<p>例: Unityの場合</p>
<pre><code>void PCU_mock_fail(const char *msg)
{
TEST_FAIL_MESSAGE(msg);
}
</code></pre></li>
</ul>
<h4>モックのAPI</h4>
<p>例として、<strong><code>Foo.h</code></strong> というヘッダファイルに</p>
<p><strong><code>int func(int a, const char *str);</code></strong></p>
<p>というプロトタイプ宣言があるとします。
このヘッダファイルに対して<code>pcunit_mock.rb</code>を実行すると、<code>mock_Foo.h</code> と <code>mock_Foo.c</code> が生成されます。
<code>mock_Foo.c</code> にはテストダブル関数<code>func()</code>が定義されます。
生成されたモックのAPIを以下に示します。</p>
<p>注:
適宜、<strong><code>Foo</code></strong> と <strong><code>func</code></strong> を実際に使用するヘッダファイル名と関数名に読み替えてください。
プロトタイプ宣言が複数ある場合は、その数だけ<code>*_expect()</code>, <code>*_set_callback()</code>, <code>*_num_calls()</code>が生成されます。</p>
<ul>
<li><p><strong><code>void mock_Foo_init(void)</code></strong></p>
<p>モックを初期化します。
モックを使用するテストコードのsetup()で呼んでください。</p></li>
<li><p><strong><code>void mock_Foo_verify(void)</code></strong></p>
<p><code>*_expect()</code> または <code>*_set_callback()</code> を使って設定された全てのエクスペクテーションを満たしたかどうかチェックします。
1つでも満たさないエクスペクテーションがあった場合はテスト失敗を出力します。
モックを使用するテストコードのteardown()で呼んでください。</p></li>
<li><p><strong><code>void func_expect(const func_Expectation *expectations, int num)</code></strong></p>
<p>テストダブル関数<code>func()</code>のエクスペクテーション(期待される引数の値、戻り値、呼び出し回数)を設定します。
<code>expectations</code>に<code>func_Expectation</code>型の配列を指定し、<code>num</code>には<code>expectations</code>の要素数を指定します。
<code>num</code>は期待される<code>func()</code>の呼び出し回数になります。</p>
<p><code>func_Expectation</code>型は次のように型定義されています。</p>
<pre><code>typedef struct {
int retval; /* テストダブル関数の戻り値を設定 */
struct {
int a; /* 期待される引数aの値を設定 */
const char *str; /* 期待される引数strの値を設定 */
} expected;
struct {
unsigned int a:1; /* 引数aの値を無視したい場合に1を設定 */
unsigned int str:1; /* 引数strの値を無視したい場合に1を設定 */
} ignored;
} func_Expectation;
</code></pre>
<p>例:</p>
<pre><code>以下のエクスペクテーションを設定します。
- func()が2回呼び出されること
- 1回目のfunc()の引数aは100であること
- 1回目のfunc()の引数strは"foo"であること
- 1回目のfunc()は200を返す
- 2回目のfunc()の引数aは200であること
- 2回目のfunc()の引数strは何でもよい
- 2回目のfunc()は300を返す
/* テスト関数 */
static void test_func_expect(void)
{
/* func_Expectationの配列をローカル変数またはstatic変数で確保。
* 配列の要素数が、期待されるfunc()の呼び出し回数となる。
* 不定値でignoredが有効にならないように、配列は必ず0クリアすること。 */
func_Expectation e[2] = {{0}};
/* エクスペクテーションの設定 */
e[0].expected.a = 100; /* 1回目の呼び出し時に期待される引数aの値 */
e[0].expected.str = "foo"; /* 1回目の呼び出し時に期待される引数strの値 */
e[0].retval = 200; /* 1回目の呼び出し時の戻り値 */
e[1].expected.a = 200; /* 2回目の呼び出し時に期待される引数aの値 */
e[1].ignored.str = 1; /* 2回目の呼び出し時の引数strは無視 */
e[1].retval = 300; /* 2回目の呼び出し時の戻り値 */
func_expect(e, sizeof e / sizeof e[0]);
/* 1回目の呼び出し。引数aが100かつ引数strが"foo" でない場合はテスト失敗を出力する */
PCU_ASSERT_EQUAL(200, func(100, "foo"));
/* 2回目の呼び出し。引数aは200でなければならないが、引数strはどんな値でもよい */
PCU_ASSERT_EQUAL(300, func(200, "bar"));
}
</code></pre></li>
<li><p><strong><code>void func_set_callback(func_Callback callback, int expected_num_calls)</code></strong></p>
<p>テストダブル関数にユーザー定義のコールバック関数を設定します。
テストダブル関数<code>func()</code>が呼ばれると、設定した<code>callback()</code>が呼ばれるようになります。
<code>func_Callback</code>型は<code>func()</code>と同じ型の関数へのポインタ型で、
<code>typedef int (*func_Callback)(int a, const char *str);</code>と型定義されています。
<code>expected_num_calls</code>に期待される<code>func()</code>の呼び出し回数を指定します。
呼び出し回数を無制限にしたい場合は、<code>expected_num_calls</code>に負の数を指定します。</p>
<p>コールバック関数を使えば、<code>*_expect()</code>より複雑なエクスペクテーションを設定することができます。
例えば、期待される引数を範囲で指定したい場合や、ポインタ引数が指す値を変更する関数を使いたい場合など、
<code>*_expect()</code>では期待する設定ができない時に使用してください。</p>
<p>例:</p>
<pre><code>以下のエクスペクテーションを設定します。
- func()が2回呼び出されること
- 1回目のfunc()の引数aの範囲は100 <= a < 200であること
- 1回目のfunc()の引数strは"foo"であること
- 1回目のfunc()は200を返す
- 2回目のfunc()の引数aは何でもよい
- 2回目のfunc()の引数strは何でもよい
- 2回目のfunc()は300を返す
/* func()と同じ型のコールバック関数 */
static int func_callback(int a, const char *str)
{
/* func_num_calls()は既に呼び出された回数を返す。これを使って分岐できる */
if (func_num_calls() == 0) {
/* 1回目の呼び出し時の引数をチェック */
PCU_ASSERT_OPERATOR(100 <= a, &&, a < 200);
PCU_ASSERT_STRING_EQUAL("foo", str);
return 200;
} else {
/* 2回目の呼び出しは引数をチェックしない */
return 300;
}
}
/* テスト関数 */
static void test_func_set_callback(void)
{
/* コールバック関数と期待される呼び出し回数の設定 */
func_set_callback(func_callback, 2);
/* 1回目の呼び出し。引数aが100 <= a < 200かつ引数strが"foo" でない場合はテスト失敗を出力する */
PCU_ASSERT_EQUAL(200, func(150, "foo"));
/* 2回目の呼び出し。2つの引数はどんな値でもよい */
PCU_ASSERT_EQUAL(300, func(200, "bar"));
}
</code></pre></li>
<li><p><strong><code>int func_num_calls(void)</code></strong></p>