From c09dd721fe3693f9bb8a4d2445c2a9ac216676f6 Mon Sep 17 00:00:00 2001
From: j8takagi <j8takagi@nifty.com>
Date: Fri, 19 Nov 2010 00:37:16 +0900
Subject: [PATCH] =?utf8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF?=
 =?utf8?q?=E3=83=AA=E3=83=B3=E3=82=B0=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

---
 sample/hoc1/Makefile                          |   2 +-
 sample/hoc1/hoc.y                             |   3 +
 sample/hoc1/test/Define.mk                    | 166 +++++++++++++-----
 sample/hoc1/test/Makefile                     |  81 ++++++---
 sample/hoc1/test/Test.mk                      |  41 +++--
 sample/hoc1/test/add2/Makefile                |   2 +
 sample/hoc1/test/bignum/0.txt                 |   4 +
 sample/hoc1/test/bignum/Makefile              |   2 +
 sample/hoc1/test/bignum/cmd                   |   1 +
 sample/hoc1/test/bignum/in.txt                |   2 +
 sample/hoc1/test/pi/0.txt                     |  22 +--
 sample/hoc1/test/test/Makefile                |   2 +
 selftest/unittest/Define.beta.mk              | 149 ++++++++++++++++
 selftest/unittest/Define.mk                   | 114 ++++++++++++
 selftest/unittest/Makefile                    |  53 ++++++
 selftest/unittest/Test.mk                     |  46 +++++
 selftest/unittest/UNITTEST.log                |   1 +
 selftest/unittest/create_testmkfile/0.mk      |   2 +
 selftest/unittest/create_testmkfile/0.txt     |   3 +
 selftest/unittest/create_testmkfile/Makefile  |   5 +
 selftest/unittest/create_testmkfile/cmd       |   1 +
 selftest/unittest/create_testmkfile/desc.txt  |   1 +
 .../unittest/create_testmkfile/testmkfile.mk  |   2 +
 selftest/unittest/desc_log/0.log              |   1 +
 selftest/unittest/desc_log/0.txt              |   2 +
 selftest/unittest/desc_log/Makefile           |   6 +
 selftest/unittest/desc_log/cmd                |   1 +
 selftest/unittest/desc_log/desc.txt           |   1 +
 selftest/unittest/exec_cmd/0.txt              |   3 +
 selftest/unittest/exec_cmd/00.txt             |   2 +
 selftest/unittest/exec_cmd/Makefile           |   5 +
 selftest/unittest/exec_cmd/cmd                |   1 +
 selftest/unittest/exec_cmd/cmd0               |   1 +
 selftest/unittest/exec_cmd/desc.txt           |   1 +
 template/Define.mk                            |  55 +++++-
 template/Group.mk                             |  29 +--
 template/Makefile                             |  19 +-
 template/Test.mk                              |  37 ++--
 38 files changed, 731 insertions(+), 138 deletions(-)
 create mode 100644 sample/hoc1/test/add2/Makefile
 create mode 100644 sample/hoc1/test/bignum/0.txt
 create mode 100644 sample/hoc1/test/bignum/Makefile
 create mode 100755 sample/hoc1/test/bignum/cmd
 create mode 100644 sample/hoc1/test/bignum/in.txt
 create mode 100644 sample/hoc1/test/test/Makefile
 create mode 100644 selftest/unittest/Define.beta.mk
 create mode 100644 selftest/unittest/Define.mk
 create mode 100644 selftest/unittest/Makefile
 create mode 100644 selftest/unittest/Test.mk
 create mode 100644 selftest/unittest/UNITTEST.log
 create mode 100644 selftest/unittest/create_testmkfile/0.mk
 create mode 100644 selftest/unittest/create_testmkfile/0.txt
 create mode 100644 selftest/unittest/create_testmkfile/Makefile
 create mode 100755 selftest/unittest/create_testmkfile/cmd
 create mode 100644 selftest/unittest/create_testmkfile/desc.txt
 create mode 100644 selftest/unittest/create_testmkfile/testmkfile.mk
 create mode 100644 selftest/unittest/desc_log/0.log
 create mode 100644 selftest/unittest/desc_log/0.txt
 create mode 100644 selftest/unittest/desc_log/Makefile
 create mode 100755 selftest/unittest/desc_log/cmd
 create mode 100644 selftest/unittest/desc_log/desc.txt
 create mode 100644 selftest/unittest/exec_cmd/0.txt
 create mode 100644 selftest/unittest/exec_cmd/00.txt
 create mode 100644 selftest/unittest/exec_cmd/Makefile
 create mode 100755 selftest/unittest/exec_cmd/cmd
 create mode 100755 selftest/unittest/exec_cmd/cmd0
 create mode 100644 selftest/unittest/exec_cmd/desc.txt

diff --git a/sample/hoc1/Makefile b/sample/hoc1/Makefile
index be721c6..f10080e 100644
--- a/sample/hoc1/Makefile
+++ b/sample/hoc1/Makefile
@@ -1,5 +1,5 @@
 CC = gcc
-CFLAGS = -g
+CFLAGS = -g -lm
 .PHPNY: clean
 hoc1: hoc.o
 	$(CC) $(CFLAGS) -o $@ $^
diff --git a/sample/hoc1/hoc.y b/sample/hoc1/hoc.y
index 1762895..98270a8 100644
--- a/sample/hoc1/hoc.y
+++ b/sample/hoc1/hoc.y
@@ -2,12 +2,14 @@
 #define YYSTYPE double          /* data type of yacc stack */
 #include <stdio.h>
 #include <ctype.h>
+#include <math.h>
 %}
 
 %token  NUMBER
 %left   '+' '-'                 /* left associative, same precedence */
 %left   '*' '/' '%'             /* left associative, higher precedence */
 %left   UNARYMINUS UNARYPLUS
+%right  '^'
 %%
 list:                           /* nothing */
         | list '\n'
@@ -19,6 +21,7 @@ expr:   NUMBER          { $$ = $1; }
         | expr '*' expr { $$ = $1 * $3; }
         | expr '/' expr { $$ = $1 / $3; }
         | expr '%' expr { $$ = (int)$1 % (int)$3; }
+        | expr '^' expr { $$ = pow($1, $3); }
         | '(' expr ')'{ $$ = $2; }
         | '-' expr %prec UNARYMINUS { $$ = -$2; }
         | '+' expr %prec UNARYPLUS { $$ = $2; }
diff --git a/sample/hoc1/test/Define.mk b/sample/hoc1/test/Define.mk
index e114af6..71b6726 100644
--- a/sample/hoc1/test/Define.mk
+++ b/sample/hoc1/test/Define.mk
@@ -1,75 +1,145 @@
-######################################################################
-# テストテンプレートのディレクトリー
-######################################################################
-# テストグループのMakefileとしてコピーされるファイル
-GROUP_MAKEFILE = Group.mk
-
 ######################################################################
 # テストグループのディレクトリー
 ######################################################################
-# グループディレクトリー
-GROUP_DIR = $(shell pwd)
-
-# グループ名。ディレクトリ名から取得
-GROUP = $(notdir $(GROUP_DIR))
-
-# テスト名。カレントディレクトリー内の、名前が大文字または.以外で始まるディレクトリー
-TESTS = $(notdir $(shell find -maxdepth 1 -name "[^A-Z.]*" -type d))
-
 # テストグループとテストの両方で使う変数を定義したファイル
-DEF_FILE = Define.mk
+DEF_FILE := Define.mk
 
 # テストのMakefileにインクルードするファイル
-TEST_MAKEFILE = Test.mk
+TEST_MAKEFILE := Test.mk
 
 # テストグループログファイル
-GROUP_LOG_FILE = $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
-
-# 成功したテストの数。テストグループログファイルから取得
-SUCCESS_TEST = $(shell grep "^[^A-Z.].*: Test Success" $(GROUP_LOG_FILE) | wc -l)
-
-# 失敗したテストの数。テストグループログファイルから取得
-FAIL_TEST = $(shell grep "^[^A-Z.].*: Test Failure" $(GROUP_LOG_FILE) | wc -l)
-
-# すべてのテストの数。
-ALL_TEST = $(shell expr $(SUCCESS_TEST) + $(FAIL_TEST))
+GROUP_LOG_FILE := $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
 
 ######################################################################
 # テストのディレクトリー
 ######################################################################
-# テスト名。カレントディレクトリー名から取得
-TEST = $(notdir $(shell pwd))
+# Makefile
+MAKEFILE := Makefile
+
+# 現在の日時
+DATE = $(shell date +"%F %T")
 
 # テストコマンドファイル
-CMD_FILE = cmd
+CMD_FILE := cmd
 
 # テスト説明ファイル
-DESC_FILE = desc.txt
+DESC_FILE := desc.txt
 
 # テスト想定結果ファイル
-TEST0_FILE = 0.txt
+TEST0_FILE := 0.txt
 
 # テスト結果ファイル
-TEST1_FILE = 1.txt
+TEST1_FILE := 1.txt
 
 # テストの、想定結果と結果の差分ファイル
-DIFF_FILE = diff.txt
+DIFF_FILE := diff.txt
 
 # テストエラーファイル
-ERR_FILE = err.txt
+ERR_FILE := err.txt
 
 # テストログファイル
-LOG_FILE = test.log
+LOG_FILE := test.log
 
-# 現在の日時
-DATE = `date +"%F %T"`
-
-# テスト実行コマンド。CMD_FILEを実行する。
-# ファイルの内容と、テスト結果を表す標準出力を、ターゲットファイルに保存。
-# エラー発生時は、エラー出力をターゲットファイルとERR_FILEに保存。
-# ターゲットファイルは、TEST0_FILEまたはTEST1_FILE
-CMD = \
-    chmod u+x $(CMD_FILE); \
-    cat $(CMD_FILE) >$@; \
-    ./$(CMD_FILE) >>$@ 2>$(ERR_FILE); \
-    if test -s $(ERR_FILE); then cat $(ERR_FILE) >>$@; else rm -f $(ERR_FILE); fi
+# 実行時間ファイル
+TIME_FILE := time.log
+
+######################################################################
+# コマンド
+######################################################################
+
+CP := cp
+
+CAT := cat
+
+MKDIR := mkdir
+
+RM := rm -f
+
+ECHO := echo
+
+TIME := /usr/bin/time
+
+DIFF := diff -c
+
+DEV_NULL := /dev/null
+
+CHMOD := chmod
+
+# TESTディレクトリーのMakefileを作成
+# 用例: $(call create_testmakefile,file)
+define create_testmkfile
+    $(foreach mkfile, $(DEF_FILE) $(TEST_MAKEFILE), $(ECHO) "include ../$(mkfile)" >>$1; )
+endef
+
+# 説明ファイルの内容を、引数のファイルに出力。
+# 用例: $(call desc_log,file)
+define desc_log
+    $(if $(wildcard $(DESC_FILE)),$(CAT) $(DESC_FILE) >>$1)
+endef
+
+# テスト実行の経過時間をファイルに出力。引数は、テスト名、コマンドファイル、出力ファイル
+# 用例: $(call time_cmd,name,file_cmd,file_out)
+define time_cmd
+    $(TIME) -f "$1: %E" >>$3 $2>$(DEV_NULL)
+    $(CAT) $3
+endef
+
+# テスト実行コマンド。引数は、コマンドファイル、出力ファイル、エラーファイル
+# ファイルの内容と、CMD_FILE実行の標準出力を、出力ファイルに保存。
+# エラー発生時は、エラー出力を出力ファイルとエラーファイルに保存。
+# 用例: $(call exec_cmd,file_cmd,file_out,file_err)
+define exec_cmd
+    $(CHMOD) u+x $1
+    $(CAT) $1 >$2
+    ./$1 >>$2 2>$3
+    if test -s $3; then $(CAT) $3 >>$2; else $(RM) $3; fi
+endef
+
+# 2つのファイルを比較し、差分ファイルを作成。引数は、ファイル0、ファイル1、差分ファイル
+# 用例: $(call diff_testfiles,file0,file1)
+define diff_testfiles
+    diff $1 $2 >$3 2>&1
+    if test ! -s $3; then $(RM) $3; fi
+endef
+
+# 差分ファイルの内容をログファイルに出力。引数は、テスト名、差分ファイル、ログファイル
+# 用例: $(call test_log,name,file_diff,file_log)
+define test_log
+    $(ECHO) "$1: Test $(if $(wildcard $2),Failure,Success) $(DATE)" >>$3
+endef
+
+# テストごとのログファイルをグループログファイルに出力。引数は、テストのリスト、グループログファイル
+# 用例: $(call group_log_each,tests,file_group_log)
+define group_log_each
+    $(foreach target,$1,$(call group_log,$(target),$2))
+endef
+
+# テストのログファイルをグループログファイルに出力。引数は、テスト、グループログファイル
+# 用例: $(call group_log_each,tests,file_group_log)
+define group_log
+    $(ECHO) >>$2
+    if test -s $1/$(LOG_FILE); then $(CAT) $1/$(LOG_FILE) >>$2; else $(ECHO) $1 ": no log." >>$2; fi
+endef
+
+LOG_GROUP = for target in $^; do ($(ECHO) <$$target/$(LOG_FILE) && $(CAT) <$$target/$(LOG_FILE)) >>$@ || $(ECHO) $$target ": no log." >>$@; done
+
+REPORT_GROUP = $(ECHO) "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
+               if test $(FAIL_TEST) -eq 0; then $(ECHO) "$(GROUP): All tests are succeded."; fi
+
+LOG_TIME_REPORT = for target in ^; do ($(ECHO)<$$target/$(LOG_FILE) && $(CAT) <$$target/$(TIME_FILE)) >>$@ || $(ECHO) $$target ": no time." >>$@; done
+
+######################################################################
+# エラー
+######################################################################
+
+# chk_var_null: 変数がNULLの場合、エラー
+# 用例: $(call chk_var_null, var)
+define chk_var_null
+    $(if $($1),,$(error $1 is NULL))
+endef
+
+# chk_file_ext: 変数で指定されたファイルが実在する場合、エラー
+# 用例: $(call chk_file_ext, var)
+define chk_file_ext
+    $(if $(wildcard $($1)),$(error $(wildcard $($1)) exists))
+endef
diff --git a/sample/hoc1/test/Makefile b/sample/hoc1/test/Makefile
index a66c1f8..31cb794 100644
--- a/sample/hoc1/test/Makefile
+++ b/sample/hoc1/test/Makefile
@@ -1,6 +1,34 @@
 # autotest.mk > template > Group.mk
 # テストグループのMakefile
-#
+
+######################################################################
+# テストグループの定義
+######################################################################
+
+include Define.mk
+
+# グループディレクトリー
+GROUP_DIR := $(shell pwd)
+
+# グループ名。ディレクトリ名から取得
+GROUP := $(notdir $(GROUP_DIR))
+
+# テスト名。カレントディレクトリー内の、名前が大文字または.以外で始まるディレクトリー
+TESTS := $(notdir $(shell find -maxdepth 1 -name "[^A-Z.]*" -type d))
+
+# 成功したテストの数。テストグループログファイルから取得
+SUCCESS_TEST = $(shell grep "^[^A-Z.].*: Test Success" $(GROUP_LOG_FILE) | wc -l)
+
+# 失敗したテストの数。テストグループログファイルから取得
+FAIL_TEST = $(shell grep "^[^A-Z.].*: Test Failure" $(GROUP_LOG_FILE) | wc -l)
+
+# すべてのテストの数
+ALL_TEST = $(shell expr $(SUCCESS_TEST) + $(FAIL_TEST))
+
+#テストグループ計時ファイル
+GROUP_TIME_FILE = $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]')_time.log
+
+######################################################################
 # オペレーター
 # make         : すべてのテストを実施し、ログファイルを作成
 # make check   : ↓
@@ -10,39 +38,44 @@
 # make report  : ログファイルから、テストの結果をレポート
 # make clean   : すべてのテストで、"make" で生成されたファイルをクリア
 # make cleanall: すべてのテストで、"make" と "make set" で生成されたファイルをクリア
-
-include Define.mk
+######################################################################
 
 .PHONY: check create set checkeach report clean cleanall
 
 check: checkeach report
 
 create:
-ifndef TEST
-	@echo "no test created. set TEST."
-else
-	@mkdir $(TEST)
-	@for ifile in $(DEF_FILE) $(TEST_MAKEFILE); do echo "include ../$$ifile" >>$(TEST)/Makefile; done
-endif
+	@$(call chk_var_null,TEST)
+	@$(call chk_file_ext,TEST)
+	@$(MKDIR) $(TEST)
+	@$(call create_testmkfile,$(TEST)/$(MAKEFILE))
 
-set:
-	@for target in $(TESTS); do $(MAKE) set -C $$target; done
+set: $(TESTS)
+	$(MAKE) set -C $^
 
-checkeach:
-	@rm -f $(GROUP_LOG_FILE)
-	@for target in $(TESTS); do $(MAKE) check -C $$target; done
+checkeach: $(TESTS)
+	@$(RM) $(GROUP_LOG_FILE)
+	TARGET=check
 
-$(GROUP_LOG_FILE):
-	@for target in $(TESTS); do (echo<$$target/$(LOG_FILE) && cat <$$target/$(LOG_FILE)) >>$@ || echo $$target ": no log." >>$@; done
+$(GROUP_LOG_FILE): $(TESTS)
+	@$(LOG_GROUP)
 
 report: $(GROUP_LOG_FILE)
-	@echo "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
-         if test $(FAIL_TEST) -eq 0; then echo "$(GROUP): All tests are succeded."; fi
+	@$(REPORT_GROUP)
+
+time: timeeach $(GROUP_TIME_FILE)
+	@$(CAT) $(GROUP_TIME_FILE)
+
+$(GROUP_TIME_FILE): $(TESTS)
+	@$(LOG_TIME_REPORT)
+
+timeeach: $(TESTS)
+	@$(MAKE) time -C $^
 
-clean:
-	@for target in $(TESTS); do $(MAKE) clean -C $$target; done
-	@rm -f $(GROUP_LOG_FILE)
+clean: $(TESTS)
+	@echo $^ && $(MAKE) clean -C $^
+	@$(RM) $(GROUP_LOG_FILE)
 
-cleanall:
-	@for target in $(TESTS); do $(MAKE) cleanall -C $$target; done
-	@rm -f $(GROUP_LOG_FILE)
+$(TESTS):
+	@echo $@
+	@$(MAKE) $(TARGET) -C $@
diff --git a/sample/hoc1/test/Test.mk b/sample/hoc1/test/Test.mk
index cf5979b..398318f 100644
--- a/sample/hoc1/test/Test.mk
+++ b/sample/hoc1/test/Test.mk
@@ -1,16 +1,22 @@
-# autotest.mk > test_template > test.mk
+# autotest.mk > test_template > Test.mk
 # 自動テスト用のMakefile
 #
 # 要: Define.mk
 #
 # オペレーター
-# make         : CMDで設定されたコマンドを実行した出力結果を1.txtに出力し、0.txtと比較し、レポート
+# make         : CMDの標準出力をTEST1_FILEに保存したあと、TEST0_FILEとの差分を比較し、結果をLOG_FILEに出力
 # make check   : ↓
-# make prepare : CMDで設定されたコマンドを実行した出力結果を0.txt(テストの想定結果)に出力
-# make clean   : 「make」で生成されたファイルをクリア
-# make cleanall: 「make」と「make prepare」で生成されたファイルをクリア
+# make set     : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は実行しない
+# make reset   : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は上書き
+# make time    : CMDの実行にかかった時間をTIME_FILEに保存し、出力
+# make cleantime: "make time" で作成されたファイルをクリア
+# make clean   : "make" で作成されたファイルをクリア
+# make cleanall: "make" と "make set" で作成されたファイルをクリア
 
-.PHONY: check set reset clean cleanall
+# テスト名。カレントディレクトリー名から取得
+TEST = $(notdir $(shell pwd))
+
+.PHONY: check set reset time cleantime clean cleanall
 
 check: clean $(LOG_FILE)
 
@@ -18,18 +24,27 @@ set: $(TEST0_FILE)
 
 reset: cleanall $(TEST0_FILE)
 
+time: cleantime $(TIME_FILE)
+
+cleantime:
+	@$(RM) $(TIME_FILE)
+
 clean:
-	@rm -f $(TEST1_FILE) $(DIFF_FILE) $(LOG_FILE) $(ERR_FILE)
+	@$(RM) $(TEST1_FILE) $(DIFF_FILE) $(LOG_FILE) $(ERR_FILE) $(TIME_FILE)
 
 cleanall: clean
-	@rm -f $(TEST0_FILE)
+	@$(RM) $(TEST0_FILE)
 
-$(TEST0_FILE) $(TEST1_FILE):
-	@if test ! -s $(CMD_FILE); then echo "set command file: $(CMD_FILE)."; else $(CMD); fi
+$(TEST0_FILE) $(TEST1_FILE): $(CMD_FILE)
+	@$(call exec_cmd,$^,$@,$(ERR_FILE))
 
 $(DIFF_FILE): $(TEST1_FILE)
-	@-diff -c $(TEST0_FILE) $(TEST1_FILE) >$@ 2>&1
+	@$(call diff_testfiles,$(TEST0_FILE),$(TEST1_FILE),$@)
 
 $(LOG_FILE): $(DIFF_FILE)
-	@if test -s $(DESC_FILE); then cat $(DESC_FILE) >>$@; fi;
-	@if test ! -s $^; then echo "$(TEST): Test Success $(DATE)"  >>$@; else echo "$(TEST): Test Failure $(DATE)" >>$@; fi;
+	@$(call desc_log,$@)
+	@$(call test_log,$(TEST),$^,$@)
+
+$(TIME_FILE): $(CMD_FILE)
+	@$(call desc_log,$@)
+	@$(call time_cmd,$(TEST),./$^,$@)
diff --git a/sample/hoc1/test/add2/Makefile b/sample/hoc1/test/add2/Makefile
new file mode 100644
index 0000000..b6dac59
--- /dev/null
+++ b/sample/hoc1/test/add2/Makefile
@@ -0,0 +1,2 @@
+include ../Define.mk
+include ../Test.mk
diff --git a/sample/hoc1/test/bignum/0.txt b/sample/hoc1/test/bignum/0.txt
new file mode 100644
index 0000000..e168ad3
--- /dev/null
+++ b/sample/hoc1/test/bignum/0.txt
@@ -0,0 +1,4 @@
+cat in.txt && ../../hoc1 < in.txt
+9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1
+
+	9999999999999999860310597602564577717002641838126363875249660735883565852672743849064846414228960666786379280392654615393353172850252103336275952370615397010730691664689375178569039851073146339641623266071126720011020169553304018596457812688561947201171488461172921822139066929851282122002676667750021070848.000000
diff --git a/sample/hoc1/test/bignum/Makefile b/sample/hoc1/test/bignum/Makefile
new file mode 100644
index 0000000..b6dac59
--- /dev/null
+++ b/sample/hoc1/test/bignum/Makefile
@@ -0,0 +1,2 @@
+include ../Define.mk
+include ../Test.mk
diff --git a/sample/hoc1/test/bignum/cmd b/sample/hoc1/test/bignum/cmd
new file mode 100755
index 0000000..ea36034
--- /dev/null
+++ b/sample/hoc1/test/bignum/cmd
@@ -0,0 +1 @@
+cat in.txt && ../../hoc1 < in.txt
diff --git a/sample/hoc1/test/bignum/in.txt b/sample/hoc1/test/bignum/in.txt
new file mode 100644
index 0000000..6547670
--- /dev/null
+++ b/sample/hoc1/test/bignum/in.txt
@@ -0,0 +1,2 @@
+9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1
+
diff --git a/sample/hoc1/test/pi/0.txt b/sample/hoc1/test/pi/0.txt
index c0dbd3e..3aa600e 100644
--- a/sample/hoc1/test/pi/0.txt
+++ b/sample/hoc1/test/pi/0.txt
@@ -11,14 +11,14 @@ cat in.txt && ../../hoc1 < in.txt
 4 * (1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 + 1/17 - 1/19 + 1/21 - 1/23 + 1/25 - 1/27 + 1/29 - 1/31 + 1/33 - 1/35 + 1/37 - 1/39 + 1/41 - 1/43 + 1/45 - 1/47 + 1/49 - 1/51 + 1/53 - 1/55 + 1/57 - 1/59 + 1/61 - 1/63 + 1/65 - 1/67 + 1/69 - 1/71 + 1/73 - 1/75 + 1/77 - 1/79 + 1/81 - 1/83 + 1/85 - 1/87 + 1/89 - 1/91 + 1/93 - 1/95 + 1/97 - 1/99 + 1/101 - 1/103 + 1/105 - 1/107 + 1/109 - 1/111 + 1/113 - 1/115 + 1/117 - 1/119 + 1/121 - 1/123 + 1/125 - 1/127 + 1/129 - 1/131 + 1/133 - 1/135 + 1/137 - 1/139 + 1/141 - 1/143 + 1/145 - 1/147 + 1/149 - 1/151 + 1/153 - 1/155 + 1/157 - 1/159 + 1/161 - 1/163 + 1/165 - 1/167 + 1/169 - 1/171 + 1/173 - 1/175 + 1/177 - 1/179 + 1/181 - 1/183 + 1/185 - 1/187 + 1/189 - 1/191 + 1/193 - 1/195 + 1/197 - 1/199 + 1/201 - 1/203 + 1/205 - 1/207 + 1/209 - 1/211 + 1/213 - 1/215 + 1/217 - 1/219 + 1/221 - 1/223 + 1/225 - 1/227 + 1/229 - 1/231 + 1/233 - 1/235 + 1/237 - 1/239 + 1/241 - 1/243 + 1/245 - 1/247 + 1/249 - 1/251 + 1/253 - 1/255 + 1/257 - 1/259 + 1/261 - 1/263 + 1/265 - 1/267 + 1/269 - 1/271 + 1/273 - 1/275 + 1/277 - 1/279 + 1/281 - 1/283 + 1/285 - 1/287 + 1/289 - 1/291 + 1/293 - 1/295 + 1/297 - 1/299 + 1/301 - 1/303 + 1/305 - 1/307 + 1/309 - 1/311 + 1/313 - 1/315 + 1/317 - 1/319 + 1/321 - 1/323 + 1/325 - 1/327 + 1/329 - 1/331 + 1/333 - 1/335 + 1/337 - 1/339 + 1/341 - 1/343 + 1/345 - 1/347 + 1/349 - 1/351 + 1/353 - 1/355 + 1/357 - 1/359 + 1/361 - 1/363 + 1/365 - 1/367 + 1/369 - 1/371 + 1/373 - 1/375 + 1/377 - 1/379 + 1/381 - 1/383 + 1/385 - 1/387 + 1/389 - 1/391 + 1/393 - 1/395 + 1/397 - 1/399 + 1/401 - 1/403 + 1/405 - 1/407 + 1/409 - 1/411 + 1/413 - 1/415 + 1/417 - 1/419 + 1/421 - 1/423 + 1/425 - 1/427 + 1/429 - 1/431 + 1/433 - 1/435 + 1/437 - 1/439 + 1/441 - 1/443 + 1/445 - 1/447 + 1/449 - 1/451 + 1/453 - 1/455 + 1/457 - 1/459 + 1/461 - 1/463 + 1/465 - 1/467 + 1/469 - 1/471 + 1/473 - 1/475 + 1/477 - 1/479 + 1/481 - 1/483 + 1/485 - 1/487 + 1/489 - 1/491 + 1/493 - 1/495 + 1/497 - 1/499 + 1/501 - 1/503 + 1/505 - 1/507 + 1/509 - 1/511 + 1/513 - 1/515 + 1/517 - 1/519 + 1/521 - 1/523 + 1/525 - 1/527 + 1/529 - 1/531 + 1/533 - 1/535 + 1/537 - 1/539 + 1/541 - 1/543 + 1/545 - 1/547 + 1/549 - 1/551 + 1/553 - 1/555 + 1/557 - 1/559 + 1/561 - 1/563 + 1/565 - 1/567 + 1/569 - 1/571 + 1/573 - 1/575 + 1/577 - 1/579 + 1/581 - 1/583 + 1/585 - 1/587 + 1/589 - 1/591 + 1/593 - 1/595 + 1/597 - 1/599 + 1/601 - 1/603 + 1/605 - 1/607 + 1/609 - 1/611 + 1/613 - 1/615 + 1/617 - 1/619 + 1/621 - 1/623 + 1/625 - 1/627 + 1/629 - 1/631 + 1/633 - 1/635 + 1/637 - 1/639 + 1/641 - 1/643 + 1/645 - 1/647 + 1/649 - 1/651 + 1/653 - 1/655 + 1/657 - 1/659 + 1/661 - 1/663 + 1/665 - 1/667 + 1/669 - 1/671 + 1/673 - 1/675 + 1/677 - 1/679 + 1/681 - 1/683 + 1/685 - 1/687 + 1/689 - 1/691 + 1/693 - 1/695 + 1/697 - 1/699 + 1/701 - 1/703 + 1/705 - 1/707 + 1/709 - 1/711 + 1/713 - 1/715 + 1/717 - 1/719 + 1/721 - 1/723 + 1/725 - 1/727 + 1/729 - 1/731 + 1/733 - 1/735 + 1/737 - 1/739 + 1/741 - 1/743 + 1/745 - 1/747 + 1/749 - 1/751 + 1/753 - 1/755 + 1/757 - 1/759 + 1/761 - 1/763 + 1/765 - 1/767 + 1/769 - 1/771 + 1/773 - 1/775 + 1/777 - 1/779 + 1/781 - 1/783 + 1/785 - 1/787 + 1/789 - 1/791 + 1/793 - 1/795 + 1/797 - 1/799 + 1/801 - 1/803 + 1/805 - 1/807 + 1/809 - 1/811 + 1/813 - 1/815 + 1/817 - 1/819 + 1/821 - 1/823 + 1/825 - 1/827 + 1/829 - 1/831 + 1/833 - 1/835 + 1/837 - 1/839 + 1/841 - 1/843 + 1/845 - 1/847 + 1/849 - 1/851 + 1/853 - 1/855 + 1/857 - 1/859 + 1/861 - 1/863 + 1/865 - 1/867 + 1/869 - 1/871 + 1/873 - 1/875 + 1/877 - 1/879 + 1/881 - 1/883 + 1/885 - 1/887 + 1/889 - 1/891 + 1/893 - 1/895 + 1/897 - 1/899 + 1/901 - 1/903 + 1/905 - 1/907 + 1/909 - 1/911 + 1/913 - 1/915 + 1/917 - 1/919 + 1/921 - 1/923 + 1/925 - 1/927 + 1/929 - 1/931 + 1/933 - 1/935 + 1/937 - 1/939 + 1/941 - 1/943 + 1/945 - 1/947 + 1/949 - 1/951 + 1/953 - 1/955 + 1/957 - 1/959 + 1/961 - 1/963 + 1/965 - 1/967 + 1/969 - 1/971 + 1/973 - 1/975 + 1/977 - 1/979 + 1/981 - 1/983 + 1/985 - 1/987 + 1/989 - 1/991 + 1/993 - 1/995 + 1/997 - 1/999)
 4 * (1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 + 1/17 - 1/19 + 1/21 - 1/23 + 1/25 - 1/27 + 1/29 - 1/31 + 1/33 - 1/35 + 1/37 - 1/39 + 1/41 - 1/43 + 1/45 - 1/47 + 1/49 - 1/51 + 1/53 - 1/55 + 1/57 - 1/59 + 1/61 - 1/63 + 1/65 - 1/67 + 1/69 - 1/71 + 1/73 - 1/75 + 1/77 - 1/79 + 1/81 - 1/83 + 1/85 - 1/87 + 1/89 - 1/91 + 1/93 - 1/95 + 1/97 - 1/99 + 1/101 - 1/103 + 1/105 - 1/107 + 1/109 - 1/111 + 1/113 - 1/115 + 1/117 - 1/119 + 1/121 - 1/123 + 1/125 - 1/127 + 1/129 - 1/131 + 1/133 - 1/135 + 1/137 - 1/139 + 1/141 - 1/143 + 1/145 - 1/147 + 1/149 - 1/151 + 1/153 - 1/155 + 1/157 - 1/159 + 1/161 - 1/163 + 1/165 - 1/167 + 1/169 - 1/171 + 1/173 - 1/175 + 1/177 - 1/179 + 1/181 - 1/183 + 1/185 - 1/187 + 1/189 - 1/191 + 1/193 - 1/195 + 1/197 - 1/199 + 1/201 - 1/203 + 1/205 - 1/207 + 1/209 - 1/211 + 1/213 - 1/215 + 1/217 - 1/219 + 1/221 - 1/223 + 1/225 - 1/227 + 1/229 - 1/231 + 1/233 - 1/235 + 1/237 - 1/239 + 1/241 - 1/243 + 1/245 - 1/247 + 1/249 - 1/251 + 1/253 - 1/255 + 1/257 - 1/259 + 1/261 - 1/263 + 1/265 - 1/267 + 1/269 - 1/271 + 1/273 - 1/275 + 1/277 - 1/279 + 1/281 - 1/283 + 1/285 - 1/287 + 1/289 - 1/291 + 1/293 - 1/295 + 1/297 - 1/299 + 1/301 - 1/303 + 1/305 - 1/307 + 1/309 - 1/311 + 1/313 - 1/315 + 1/317 - 1/319 + 1/321 - 1/323 + 1/325 - 1/327 + 1/329 - 1/331 + 1/333 - 1/335 + 1/337 - 1/339 + 1/341 - 1/343 + 1/345 - 1/347 + 1/349 - 1/351 + 1/353 - 1/355 + 1/357 - 1/359 + 1/361 - 1/363 + 1/365 - 1/367 + 1/369 - 1/371 + 1/373 - 1/375 + 1/377 - 1/379 + 1/381 - 1/383 + 1/385 - 1/387 + 1/389 - 1/391 + 1/393 - 1/395 + 1/397 - 1/399 + 1/401 - 1/403 + 1/405 - 1/407 + 1/409 - 1/411 + 1/413 - 1/415 + 1/417 - 1/419 + 1/421 - 1/423 + 1/425 - 1/427 + 1/429 - 1/431 + 1/433 - 1/435 + 1/437 - 1/439 + 1/441 - 1/443 + 1/445 - 1/447 + 1/449 - 1/451 + 1/453 - 1/455 + 1/457 - 1/459 + 1/461 - 1/463 + 1/465 - 1/467 + 1/469 - 1/471 + 1/473 - 1/475 + 1/477 - 1/479 + 1/481 - 1/483 + 1/485 - 1/487 + 1/489 - 1/491 + 1/493 - 1/495 + 1/497 - 1/499 + 1/501 - 1/503 + 1/505 - 1/507 + 1/509 - 1/511 + 1/513 - 1/515 + 1/517 - 1/519 + 1/521 - 1/523 + 1/525 - 1/527 + 1/529 - 1/531 + 1/533 - 1/535 + 1/537 - 1/539 + 1/541 - 1/543 + 1/545 - 1/547 + 1/549 - 1/551 + 1/553 - 1/555 + 1/557 - 1/559 + 1/561 - 1/563 + 1/565 - 1/567 + 1/569 - 1/571 + 1/573 - 1/575 + 1/577 - 1/579 + 1/581 - 1/583 + 1/585 - 1/587 + 1/589 - 1/591 + 1/593 - 1/595 + 1/597 - 1/599 + 1/601 - 1/603 + 1/605 - 1/607 + 1/609 - 1/611 + 1/613 - 1/615 + 1/617 - 1/619 + 1/621 - 1/623 + 1/625 - 1/627 + 1/629 - 1/631 + 1/633 - 1/635 + 1/637 - 1/639 + 1/641 - 1/643 + 1/645 - 1/647 + 1/649 - 1/651 + 1/653 - 1/655 + 1/657 - 1/659 + 1/661 - 1/663 + 1/665 - 1/667 + 1/669 - 1/671 + 1/673 - 1/675 + 1/677 - 1/679 + 1/681 - 1/683 + 1/685 - 1/687 + 1/689 - 1/691 + 1/693 - 1/695 + 1/697 - 1/699 + 1/701 - 1/703 + 1/705 - 1/707 + 1/709 - 1/711 + 1/713 - 1/715 + 1/717 - 1/719 + 1/721 - 1/723 + 1/725 - 1/727 + 1/729 - 1/731 + 1/733 - 1/735 + 1/737 - 1/739 + 1/741 - 1/743 + 1/745 - 1/747 + 1/749 - 1/751 + 1/753 - 1/755 + 1/757 - 1/759 + 1/761 - 1/763 + 1/765 - 1/767 + 1/769 - 1/771 + 1/773 - 1/775 + 1/777 - 1/779 + 1/781 - 1/783 + 1/785 - 1/787 + 1/789 - 1/791 + 1/793 - 1/795 + 1/797 - 1/799 + 1/801 - 1/803 + 1/805 - 1/807 + 1/809 - 1/811 + 1/813 - 1/815 + 1/817 - 1/819 + 1/821 - 1/823 + 1/825 - 1/827 + 1/829 - 1/831 + 1/833 - 1/835 + 1/837 - 1/839 + 1/841 - 1/843 + 1/845 - 1/847 + 1/849 - 1/851 + 1/853 - 1/855 + 1/857 - 1/859 + 1/861 - 1/863 + 1/865 - 1/867 + 1/869 - 1/871 + 1/873 - 1/875 + 1/877 - 1/879 + 1/881 - 1/883 + 1/885 - 1/887 + 1/889 - 1/891 + 1/893 - 1/895 + 1/897 - 1/899 + 1/901 - 1/903 + 1/905 - 1/907 + 1/909 - 1/911 + 1/913 - 1/915 + 1/917 - 1/919 + 1/921 - 1/923 + 1/925 - 1/927 + 1/929 - 1/931 + 1/933 - 1/935 + 1/937 - 1/939 + 1/941 - 1/943 + 1/945 - 1/947 + 1/949 - 1/951 + 1/953 - 1/955 + 1/957 - 1/959 + 1/961 - 1/963 + 1/965 - 1/967 + 1/969 - 1/971 + 1/973 - 1/975 + 1/977 - 1/979 + 1/981 - 1/983 + 1/985 - 1/987 + 1/989 - 1/991 + 1/993 - 1/995 + 1/997 - 1/999 + 1/1001)
 
-	3.3396825
-	3.0418396
-	3.1891848
-	3.1638121
-	3.1198561
-	3.1628668
-	3.1207616
-	3.1619987
-	3.1215947
-	3.1395927
-	3.1435887
+	3.339683
+	3.041840
+	3.189185
+	3.163812
+	3.119856
+	3.162867
+	3.120762
+	3.161999
+	3.121595
+	3.139593
+	3.143589
diff --git a/sample/hoc1/test/test/Makefile b/sample/hoc1/test/test/Makefile
new file mode 100644
index 0000000..b6dac59
--- /dev/null
+++ b/sample/hoc1/test/test/Makefile
@@ -0,0 +1,2 @@
+include ../Define.mk
+include ../Test.mk
diff --git a/selftest/unittest/Define.beta.mk b/selftest/unittest/Define.beta.mk
new file mode 100644
index 0000000..b9ba0ff
--- /dev/null
+++ b/selftest/unittest/Define.beta.mk
@@ -0,0 +1,149 @@
+######################################################################
+# テストグループのディレクトリー
+######################################################################
+# テストグループとテストの両方で使う変数を定義したファイル
+DEF_FILE := Define.mk
+
+# テストのMakefileにインクルードするファイル
+TEST_MAKEFILE := Test.mk
+
+# テストグループログファイル
+GROUP_LOG_FILE := $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
+
+# テストグループ実行時間ファイル
+GROUP_TIME_FILE := $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]')_time.log
+
+######################################################################
+# テストのディレクトリー
+######################################################################
+# Makefile
+MAKEFILE := Makefile
+
+# 現在の日時
+DATE = $(shell date +"%F %T")
+
+# テストコマンドファイル
+CMD_FILE := cmd
+
+# テスト説明ファイル
+DESC_FILE := desc.txt
+
+# テスト想定結果ファイル
+TEST0_FILE := 0.txt
+
+# テスト結果ファイル
+TEST1_FILE := 1.txt
+
+# テストの、想定結果と結果の差分ファイル
+DIFF_FILE := diff.txt
+
+# テストエラーファイル
+ERR_FILE := err.txt
+
+# テストログファイル
+LOG_FILE := test.log
+
+# 実行時間ファイル
+TIME_FILE := time.log
+
+######################################################################
+# コマンド
+######################################################################
+
+CP := cp
+
+CAT := cat
+
+MKDIR := mkdir
+
+RM := rm -f
+
+ECHO := echo
+
+TIME := /usr/bin/time
+
+DIFF := diff -c
+
+DEV_NULL := /dev/null
+
+CHMOD := chmod
+
+# TESTディレクトリーのMakefileを作成
+# 用例: $(call create_testmakefile,file)
+define create_testmkfile
+    $(RM) $1
+    $(foreach mkfile, $(DEF_FILE) $(TEST_MAKEFILE), $(ECHO) "include ../$(mkfile)" >>$1; )
+endef
+
+# 説明ファイルの内容を、引数のファイルに出力。
+# 用例: $(call desc_log,file_out)
+define desc_log
+    $(if $(wildcard $(DESC_FILE)),$(CAT) $(DESC_FILE) >>$1)
+endef
+
+# テスト実行の経過時間をファイルに出力。引数は、テスト名、コマンドファイル、出力ファイル
+# 用例: $(call time_cmd,name,file_cmd,file_out)
+define time_cmd
+    $(TIME) -f "$1: %E" >>$3 $2>$(DEV_NULL)
+    $(CAT) $3
+endef
+
+# テスト実行コマンド。引数は、コマンドファイル、出力ファイル、エラーファイル
+# ファイルの内容と、CMD_FILE実行の標準出力を、出力ファイルに保存。
+# エラー発生時は、エラー出力を出力ファイルとエラーファイルに保存。
+# 用例: $(call exec_cmd,file_cmd,file_out,file_err)
+define exec_cmd
+    $(CHMOD) u+x $1
+    $(CAT) $1 >$2
+    ./$1 >>$2 2>$3
+    if test -s $3; then $(CAT) $3 >>$2; else $(RM) $3; fi
+endef
+
+# 2つのファイルを比較し、差分ファイルを作成。引数は、ファイル0、ファイル1、差分ファイル
+# 用例: $(call diff_testfiles,file0,file1)
+define diff_testfiles
+    diff $1 $2 >$3 2>&1
+    if test ! -s $3; then $(RM) $3; fi
+endef
+
+# 差分ファイルの内容をログファイルに出力。引数は、テスト名、差分ファイル、ログファイル
+# 用例: $(call test_log,name,file_diff,file_log)
+define test_log
+    $(ECHO) "$1: Test $(if $(wildcard $2),Failure,Success) $(DATE)" >>$3
+endef
+
+# テストごとのログファイルをグループログファイルに出力。引数は、テストのリスト、グループログファイル
+# 用例: $(call group_log_each,tests,file_group_log)
+define group_log_each
+    $(foreach target,$1,$(call group_log,$(target),$2))
+endef
+
+# テストのログファイルをグループログファイルに出力。引数は、テスト、グループログファイル
+# 用例: $(call group_log_each,tests,file_group_log)
+define group_log
+    $(ECHO) >>$2
+    if test -s $1/$(LOG_FILE); then $(CAT) $1/$(LOG_FILE) >>$2; else $(ECHO) $1 ": no log." >>$2; fi
+endef
+
+LOG_GROUP = for target in $^; do ($(ECHO) <$$target/$(LOG_FILE) && $(CAT) <$$target/$(LOG_FILE)) >>$@ || $(ECHO) $$target ": no log." >>$@; done
+
+REPORT_GROUP = $(ECHO) "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
+               if test $(FAIL_TEST) -eq 0; then $(ECHO) "$(GROUP): All tests are succeded."; fi
+
+LOG_TIME_REPORT = for target in ^; do ($(ECHO)<$$target/$(LOG_FILE) && $(CAT) <$$target/$(TIME_FILE)) >>$@ || $(ECHO) $$target ": no time." >>$@; done
+
+######################################################################
+# エラー
+######################################################################
+
+# chk_var_null: 変数がNULLの場合、エラー
+# 用例: $(call chk_var_null, var)
+define chk_var_null
+    $(if $($1),,$(error $1 is NULL))
+endef
+
+# chk_file_ext: 変数で指定されたファイルが実在する場合、エラー
+# 用例: $(call chk_file_ext, var)
+define chk_file_ext
+    $(if $(wildcard $($1)),$(error $(wildcard $($1)) exists))
+endef
diff --git a/selftest/unittest/Define.mk b/selftest/unittest/Define.mk
new file mode 100644
index 0000000..943f724
--- /dev/null
+++ b/selftest/unittest/Define.mk
@@ -0,0 +1,114 @@
+######################################################################
+# テストテンプレートのディレクトリー
+######################################################################
+# テストグループのMakefileとしてコピーされるファイル
+GROUP_MAKEFILE = Group.mk
+
+######################################################################
+# テストグループのディレクトリー
+######################################################################
+# グループディレクトリー
+GROUP_DIR = $(shell pwd)
+
+# グループ名。ディレクトリ名から取得
+GROUP = $(notdir $(GROUP_DIR))
+
+# テスト名。カレントディレクトリー内の、名前が大文字または.以外で始まるディレクトリー
+TESTS = $(notdir $(shell find -maxdepth 1 -name "[^A-Z.]*" -type d))
+
+# テストグループとテストの両方で使う変数を定義したファイル
+DEF_FILE = Define.mk
+
+# テストのMakefileにインクルードするファイル
+TEST_MAKEFILE = Test.mk
+
+# テストグループログファイル
+GROUP_LOG_FILE = $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
+
+# 成功したテストの数。テストグループログファイルから取得
+SUCCESS_TEST = $(shell grep "^[^A-Z.].*: Test Success" $(GROUP_LOG_FILE) | wc -l)
+
+# 失敗したテストの数。テストグループログファイルから取得
+FAIL_TEST = $(shell grep "^[^A-Z.].*: Test Failure" $(GROUP_LOG_FILE) | wc -l)
+
+# すべてのテストの数
+ALL_TEST = $(shell expr $(SUCCESS_TEST) + $(FAIL_TEST))
+
+#テストグループ計時ファイル
+GROUP_TIME_FILE = $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
+
+######################################################################
+# テストのディレクトリー
+######################################################################
+# テスト名。カレントディレクトリー名から取得
+TEST = $(notdir $(shell pwd))
+
+# 現在の日時
+DATE = $(shell date +"%F %T")
+
+# テストコマンドファイル
+CMD_FILE = cmd
+
+# テスト説明ファイル
+DESC_FILE = desc.txt
+
+# テスト想定結果ファイル
+TEST0_FILE = 0.txt
+
+# テスト結果ファイル
+TEST1_FILE = 1.txt
+
+# テストの、想定結果と結果の差分ファイル
+DIFF_FILE = diff.txt
+
+# テストエラーファイル
+ERR_FILE = err.txt
+
+# テストログファイル
+LOG_FILE = test.log
+
+# 実行時間ファイル
+TIME_FILE = time.log
+
+######################################################################
+# コマンド
+######################################################################
+
+CP := cp
+
+CAT := cat
+
+MKDIR := mkdir
+
+RM := rm -f
+
+ECHO := echo
+
+TIME := /usr/bin/time
+
+DIFF := diff -c
+
+DEV_NULL := /dev/null
+
+CHMOD := chmod
+
+DESC = if test -s $(DESC_FILE); then cat $(DESC_FILE) >>$@; fi;
+
+# 2ファイルの差分を出力。引数は2ファイル
+DIFF = diff -c
+
+# ファイルを実行可能にする。引数は1ファイル
+CHMOD = chmod u+x
+
+# テスト実行コマンド。
+# ファイルの内容と、CMD_FILE実行の標準出力を、ターゲットファイルに保存。
+# エラー発生時は、エラー出力をターゲットファイルとERR_FILEに保存。
+# ターゲットファイルは、TEST0_FILEまたはTEST1_FILE
+CMD = \
+    $(CHMOD) $(CMD_FILE); \
+    $(CAT) $(CMD_FILE) >$@; \
+    ./$(CMD_FILE) >>$@ 2>$(ERR_FILE); \
+    if test -s $(ERR_FILE); then $(CAT) $(ERR_FILE) >>$@; else $(RM) $(ERR_FILE); fi
+
+# テストの結果をログに出力
+REPORT_TEST = if test ! -s $^; then $(ECHO) "$(TEST): Test Success $(DATE)"  >>$@; else $(ECHO) "$(TEST): Test Failure $(DATE)" >>$@; fi;
diff --git a/selftest/unittest/Makefile b/selftest/unittest/Makefile
new file mode 100644
index 0000000..f31df90
--- /dev/null
+++ b/selftest/unittest/Makefile
@@ -0,0 +1,53 @@
+# autotest.mk > template > Group.mk
+# テストグループのMakefile
+#
+# オペレーター
+# make         : すべてのテストを実施し、ログファイルを作成
+# make check   : ↓
+# make create  : TESTNAMEで指定されたテストを新規に作成
+# make set     : すべてのテストの、想定結果を出力
+# make checkeach: すべてのテストを実施
+# make report  : ログファイルから、テストの結果をレポート
+# make clean   : すべてのテストで、"make" で生成されたファイルをクリア
+# make cleanall: すべてのテストで、"make" と "make set" で生成されたファイルをクリア
+
+include Define.beta.mk
+
+.PHONY: check create set checkeach report clean cleanall
+
+check: checkeach report
+
+create:
+ifndef TEST
+	@$(ECHO) "no test created. set TEST."
+else
+	@$(MKDIR) $(TEST)
+	@for ifile in $(DEF_FILE) $(TEST_MAKEFILE); do $(ECHO) "include ../$$ifile" >>$(TEST)/Makefile; done
+endif
+
+set:
+	@for target in $(TESTS); do $(MAKE) set -C $$target; done
+
+checkeach:
+	@$(RM) $(GROUP_LOG_FILE)
+	@for target in $(TESTS); do $(MAKE) check -C $$target; done
+
+$(GROUP_LOG_FILE):
+	@for target in $(TESTS); do ($(ECHO) <$$target/$(LOG_FILE) && $(CAT) <$$target/$(LOG_FILE)) >>$@ || $(ECHO) $$target ": no log." >>$@; done
+
+report: $(GROUP_LOG_FILE)
+	@$(ECHO) "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
+         if test $(FAIL_TEST) -eq 0; then $(ECHO) "$(GROUP): All tests are succeded."; fi
+
+time: timeeach $(GROUP_TIME_FILE)
+	@$(CAT) $(GROUP_TIME_FILE)
+
+$(GROUP_TIME_FILE):
+	@for target in $(TESTS); do ($(ECHO)<$$target/$(LOG_FILE) && $(CAT) <$$target/$(TIME_FILE)) >>$@ || $(ECHO) $$target ": no time." >>$@; done
+
+timeeach:
+	@for target in $(TESTS); do $(MAKE) time -C $$target; done
+
+clean:
+	@for target in $(TESTS); do $(MAKE) clean -C $$target; done
+	@$(RM) $(GROUP_LOG_FILE)
diff --git a/selftest/unittest/Test.mk b/selftest/unittest/Test.mk
new file mode 100644
index 0000000..0237f11
--- /dev/null
+++ b/selftest/unittest/Test.mk
@@ -0,0 +1,46 @@
+# autotest.mk > test_template > Test.mk
+# 自動テスト用のMakefile
+#
+# 要: Define.mk
+#
+# オペレーター
+# make         : CMDの標準出力をTEST1_FILEに保存したあと、TEST0_FILEとの差分を比較し、結果をLOG_FILEに出力
+# make check   : ↓
+# make set     : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は実行しない
+# make reset   : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は上書き
+# make time    : CMDの実行にかかった時間をTIME_FILEに保存し、出力
+# make cleantime: "make time" で作成されたファイルをクリア
+# make clean   : "make" で作成されたファイルをクリア
+# make cleanall: "make" と "make set" で作成されたファイルをクリア
+
+.PHONY: check set reset time cleantime clean cleanall
+
+check: clean $(LOG_FILE)
+
+set: $(TEST0_FILE)
+
+reset: cleanall $(TEST0_FILE)
+
+time: cleantime $(TIME_FILE)
+
+cleantime:
+	@$(RM) $(TIME_FILE)
+
+clean:
+	@$(RM) $(TEST1_FILE) $(DIFF_FILE) $(LOG_FILE) $(ERR_FILE) $(TIME_FILE)
+
+cleanall: clean
+	@$(RM) $(TEST0_FILE)
+
+$(TEST0_FILE) $(TEST1_FILE): $(CMD_FILE)
+	@$(call exec_cmd,$^,$@,$(ERR_FILE))
+
+$(DIFF_FILE): $(TEST1_FILE)
+	@-$(DIFF) $(TEST0_FILE) $(TEST1_FILE) >$@ 2>&1
+
+$(LOG_FILE): $(DIFF_FILE)
+	@$(DESC)
+	@$(REPORT_TEST)
+
+$(TIME_FILE): $(CMD_FILE)
+	@$(TIME) ./$(CMD_FILE) 1>/dev/null && $(CAT) $@
diff --git a/selftest/unittest/UNITTEST.log b/selftest/unittest/UNITTEST.log
new file mode 100644
index 0000000..073685d
--- /dev/null
+++ b/selftest/unittest/UNITTEST.log
@@ -0,0 +1 @@
+create_testmkfile : no time.
diff --git a/selftest/unittest/create_testmkfile/0.mk b/selftest/unittest/create_testmkfile/0.mk
new file mode 100644
index 0000000..b6dac59
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/0.mk
@@ -0,0 +1,2 @@
+include ../Define.mk
+include ../Test.mk
diff --git a/selftest/unittest/create_testmkfile/0.txt b/selftest/unittest/create_testmkfile/0.txt
new file mode 100644
index 0000000..52c493f
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/0.txt
@@ -0,0 +1,3 @@
+make -s utest && cat 0.mk
+include ../Define.mk
+include ../Test.mk
diff --git a/selftest/unittest/create_testmkfile/Makefile b/selftest/unittest/create_testmkfile/Makefile
new file mode 100644
index 0000000..04dbf90
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/Makefile
@@ -0,0 +1,5 @@
+include ../Define.beta.mk
+include ../Test.mk
+
+utest:
+	$(call create_testmkfile,0.mk)
diff --git a/selftest/unittest/create_testmkfile/cmd b/selftest/unittest/create_testmkfile/cmd
new file mode 100755
index 0000000..af4f97e
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/cmd
@@ -0,0 +1 @@
+make -s utest && cat 0.mk
diff --git a/selftest/unittest/create_testmkfile/desc.txt b/selftest/unittest/create_testmkfile/desc.txt
new file mode 100644
index 0000000..a9ada04
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/desc.txt
@@ -0,0 +1 @@
+TESTディレクトリーのMakefileを作成
diff --git a/selftest/unittest/create_testmkfile/testmkfile.mk b/selftest/unittest/create_testmkfile/testmkfile.mk
new file mode 100644
index 0000000..b6dac59
--- /dev/null
+++ b/selftest/unittest/create_testmkfile/testmkfile.mk
@@ -0,0 +1,2 @@
+include ../Define.mk
+include ../Test.mk
diff --git a/selftest/unittest/desc_log/0.log b/selftest/unittest/desc_log/0.log
new file mode 100644
index 0000000..2669eb2
--- /dev/null
+++ b/selftest/unittest/desc_log/0.log
@@ -0,0 +1 @@
+説明ファイルの内容を、引数のファイルに出力
diff --git a/selftest/unittest/desc_log/0.txt b/selftest/unittest/desc_log/0.txt
new file mode 100644
index 0000000..b49f821
--- /dev/null
+++ b/selftest/unittest/desc_log/0.txt
@@ -0,0 +1,2 @@
+make -s utest && cat 0.log
+説明ファイルの内容を、引数のファイルに出力
diff --git a/selftest/unittest/desc_log/Makefile b/selftest/unittest/desc_log/Makefile
new file mode 100644
index 0000000..34bed81
--- /dev/null
+++ b/selftest/unittest/desc_log/Makefile
@@ -0,0 +1,6 @@
+include ../Define.beta.mk
+include ../Test.mk
+
+utest:
+	$(RM) 0.log
+	$(call desc_log,0.log)
diff --git a/selftest/unittest/desc_log/cmd b/selftest/unittest/desc_log/cmd
new file mode 100755
index 0000000..79c4c9e
--- /dev/null
+++ b/selftest/unittest/desc_log/cmd
@@ -0,0 +1 @@
+make -s utest && cat 0.log
diff --git a/selftest/unittest/desc_log/desc.txt b/selftest/unittest/desc_log/desc.txt
new file mode 100644
index 0000000..2669eb2
--- /dev/null
+++ b/selftest/unittest/desc_log/desc.txt
@@ -0,0 +1 @@
+説明ファイルの内容を、引数のファイルに出力
diff --git a/selftest/unittest/exec_cmd/0.txt b/selftest/unittest/exec_cmd/0.txt
new file mode 100644
index 0000000..02c12fb
--- /dev/null
+++ b/selftest/unittest/exec_cmd/0.txt
@@ -0,0 +1,3 @@
+make -s utest && cat 00.txt
+expr 2 + 3
+5
diff --git a/selftest/unittest/exec_cmd/00.txt b/selftest/unittest/exec_cmd/00.txt
new file mode 100644
index 0000000..2333bdb
--- /dev/null
+++ b/selftest/unittest/exec_cmd/00.txt
@@ -0,0 +1,2 @@
+expr 2 + 3
+5
diff --git a/selftest/unittest/exec_cmd/Makefile b/selftest/unittest/exec_cmd/Makefile
new file mode 100644
index 0000000..4c6f8b6
--- /dev/null
+++ b/selftest/unittest/exec_cmd/Makefile
@@ -0,0 +1,5 @@
+include ../Define.beta.mk
+include ../Test.mk
+
+utest:
+	$(call exec_cmd,cmd0,00.txt,uerr.txt)
diff --git a/selftest/unittest/exec_cmd/cmd b/selftest/unittest/exec_cmd/cmd
new file mode 100755
index 0000000..52943b1
--- /dev/null
+++ b/selftest/unittest/exec_cmd/cmd
@@ -0,0 +1 @@
+make -s utest && cat 00.txt
diff --git a/selftest/unittest/exec_cmd/cmd0 b/selftest/unittest/exec_cmd/cmd0
new file mode 100755
index 0000000..e7457ab
--- /dev/null
+++ b/selftest/unittest/exec_cmd/cmd0
@@ -0,0 +1 @@
+expr 2 + 3
diff --git a/selftest/unittest/exec_cmd/desc.txt b/selftest/unittest/exec_cmd/desc.txt
new file mode 100644
index 0000000..a9ada04
--- /dev/null
+++ b/selftest/unittest/exec_cmd/desc.txt
@@ -0,0 +1 @@
+TESTディレクトリーのMakefileを作成
diff --git a/template/Define.mk b/template/Define.mk
index e114af6..943f724 100644
--- a/template/Define.mk
+++ b/template/Define.mk
@@ -31,15 +31,21 @@ SUCCESS_TEST = $(shell grep "^[^A-Z.].*: Test Success" $(GROUP_LOG_FILE) | wc -l
 # 失敗したテストの数。テストグループログファイルから取得
 FAIL_TEST = $(shell grep "^[^A-Z.].*: Test Failure" $(GROUP_LOG_FILE) | wc -l)
 
-# すべてのテストの数。
+# すべてのテストの数
 ALL_TEST = $(shell expr $(SUCCESS_TEST) + $(FAIL_TEST))
 
+#テストグループ計時ファイル
+GROUP_TIME_FILE = $(shell echo $(GROUP) | tr '[a-z]' '[A-Z]').log
+
 ######################################################################
 # テストのディレクトリー
 ######################################################################
 # テスト名。カレントディレクトリー名から取得
 TEST = $(notdir $(shell pwd))
 
+# 現在の日時
+DATE = $(shell date +"%F %T")
+
 # テストコマンドファイル
 CMD_FILE = cmd
 
@@ -61,15 +67,48 @@ ERR_FILE = err.txt
 # テストログファイル
 LOG_FILE = test.log
 
-# 現在の日時
-DATE = `date +"%F %T"`
+# 実行時間ファイル
+TIME_FILE = time.log
+
+######################################################################
+# コマンド
+######################################################################
+
+CP := cp
+
+CAT := cat
+
+MKDIR := mkdir
 
-# テスト実行コマンド。CMD_FILEを実行する。
-# ファイルの内容と、テスト結果を表す標準出力を、ターゲットファイルに保存。
+RM := rm -f
+
+ECHO := echo
+
+TIME := /usr/bin/time
+
+DIFF := diff -c
+
+DEV_NULL := /dev/null
+
+CHMOD := chmod
+
+DESC = if test -s $(DESC_FILE); then cat $(DESC_FILE) >>$@; fi;
+
+# 2ファイルの差分を出力。引数は2ファイル
+DIFF = diff -c
+
+# ファイルを実行可能にする。引数は1ファイル
+CHMOD = chmod u+x
+
+# テスト実行コマンド。
+# ファイルの内容と、CMD_FILE実行の標準出力を、ターゲットファイルに保存。
 # エラー発生時は、エラー出力をターゲットファイルとERR_FILEに保存。
 # ターゲットファイルは、TEST0_FILEまたはTEST1_FILE
 CMD = \
-    chmod u+x $(CMD_FILE); \
-    cat $(CMD_FILE) >$@; \
+    $(CHMOD) $(CMD_FILE); \
+    $(CAT) $(CMD_FILE) >$@; \
     ./$(CMD_FILE) >>$@ 2>$(ERR_FILE); \
-    if test -s $(ERR_FILE); then cat $(ERR_FILE) >>$@; else rm -f $(ERR_FILE); fi
+    if test -s $(ERR_FILE); then $(CAT) $(ERR_FILE) >>$@; else $(RM) $(ERR_FILE); fi
+
+# テストの結果をログに出力
+REPORT_TEST = if test ! -s $^; then $(ECHO) "$(TEST): Test Success $(DATE)"  >>$@; else $(ECHO) "$(TEST): Test Failure $(DATE)" >>$@; fi;
diff --git a/template/Group.mk b/template/Group.mk
index a66c1f8..ef976d2 100644
--- a/template/Group.mk
+++ b/template/Group.mk
@@ -19,30 +19,35 @@ check: checkeach report
 
 create:
 ifndef TEST
-	@echo "no test created. set TEST."
+	@$(ECHO) "no test created. set TEST."
 else
-	@mkdir $(TEST)
-	@for ifile in $(DEF_FILE) $(TEST_MAKEFILE); do echo "include ../$$ifile" >>$(TEST)/Makefile; done
+	@$(MKDIR) $(TEST)
+	@for ifile in $(DEF_FILE) $(TEST_MAKEFILE); do $(ECHO) "include ../$$ifile" >>$(TEST)/Makefile; done
 endif
 
 set:
 	@for target in $(TESTS); do $(MAKE) set -C $$target; done
 
 checkeach:
-	@rm -f $(GROUP_LOG_FILE)
+	@$(RM) $(GROUP_LOG_FILE)
 	@for target in $(TESTS); do $(MAKE) check -C $$target; done
 
 $(GROUP_LOG_FILE):
-	@for target in $(TESTS); do (echo<$$target/$(LOG_FILE) && cat <$$target/$(LOG_FILE)) >>$@ || echo $$target ": no log." >>$@; done
+	@for target in $(TESTS); do ($(ECHO) <$$target/$(LOG_FILE) && $(CAT) <$$target/$(LOG_FILE)) >>$@ || $(ECHO) $$target ": no log." >>$@; done
 
 report: $(GROUP_LOG_FILE)
-	@echo "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
-         if test $(FAIL_TEST) -eq 0; then echo "$(GROUP): All tests are succeded."; fi
+	@$(ECHO) "$(GROUP): $(SUCCESS_TEST) / $(ALL_TEST) tests passed. Details in `pwd`/$(GROUP_LOG_FILE)"; \
+         if test $(FAIL_TEST) -eq 0; then $(ECHO) "$(GROUP): All tests are succeded."; fi
+
+time: timeeach $(GROUP_TIME_FILE)
+	@$(CAT) $(GROUP_TIME_FILE)
+
+$(GROUP_TIME_FILE):
+	@for target in $(TESTS); do ($(ECHO)<$$target/$(LOG_FILE) && $(CAT) <$$target/$(TIME_FILE)) >>$@ || $(ECHO) $$target ": no time." >>$@; done
+
+timeeach:
+	@for target in $(TESTS); do $(MAKE) time -C $$target; done
 
 clean:
 	@for target in $(TESTS); do $(MAKE) clean -C $$target; done
-	@rm -f $(GROUP_LOG_FILE)
-
-cleanall:
-	@for target in $(TESTS); do $(MAKE) cleanall -C $$target; done
-	@rm -f $(GROUP_LOG_FILE)
+	@$(RM) $(GROUP_LOG_FILE)
diff --git a/template/Makefile b/template/Makefile
index 92f36c5..0385c8f 100644
--- a/template/Makefile
+++ b/template/Makefile
@@ -5,14 +5,17 @@
 # make            : テストグループディレクトリーを作成
 # make creategroup: ↓
 
+# 変数やマクロの定義
 include Define.mk
 
+# テストグループのMakefileとしてコピーされるファイル
+GROUP_MAKEFILE := Group.mk
+
+# テストグループディレクトリーを作成
 creategroup:
-ifndef GROUPDIR
-	@echo "no test group created. set GROUPDIR."
-else
-	@mkdir $(GROUPDIR)
-	@cp $(GROUP_MAKEFILE) $(GROUPDIR)/Makefile
-	@cp $(TEST_MAKEFILE) $(GROUPDIR)/
-	@cp $(DEF_FILE) $(GROUPDIR)/
-endif
+	@$(call err_var_null,GROUPDIR)
+	@$(call err_file_ext,GROUPDIR)
+	@$(MKDIR) $(GROUPDIR)
+	@$(CP) $(GROUP_MAKEFILE) $(GROUPDIR)/Makefile
+	@$(CP) $(TEST_MAKEFILE) $(GROUPDIR)/
+	@$(CP) $(DEF_FILE) $(GROUPDIR)/
diff --git a/template/Test.mk b/template/Test.mk
index cf5979b..5962b23 100644
--- a/template/Test.mk
+++ b/template/Test.mk
@@ -1,16 +1,19 @@
-# autotest.mk > test_template > test.mk
+# autotest.mk > test_template > Test.mk
 # 自動テスト用のMakefile
 #
 # 要: Define.mk
 #
 # オペレーター
-# make         : CMDで設定されたコマンドを実行した出力結果を1.txtに出力し、0.txtと比較し、レポート
+# make         : CMDの標準出力をTEST1_FILEに保存したあと、TEST0_FILEとの差分を比較し、結果をLOG_FILEに出力
 # make check   : ↓
-# make prepare : CMDで設定されたコマンドを実行した出力結果を0.txt(テストの想定結果)に出力
-# make clean   : 「make」で生成されたファイルをクリア
-# make cleanall: 「make」と「make prepare」で生成されたファイルをクリア
+# make set     : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は実行しない
+# make reset   : CMDの標準出力をTEST0_FILEに保存。TEST0_FILEが存在する場合は上書き
+# make time    : CMDの実行にかかった時間をTIME_FILEに保存し、出力
+# make cleantime: "make time" で作成されたファイルをクリア
+# make clean   : "make" で作成されたファイルをクリア
+# make cleanall: "make" と "make set" で作成されたファイルをクリア
 
-.PHONY: check set reset clean cleanall
+.PHONY: check set reset time cleantime clean cleanall
 
 check: clean $(LOG_FILE)
 
@@ -18,18 +21,26 @@ set: $(TEST0_FILE)
 
 reset: cleanall $(TEST0_FILE)
 
+time: cleantime $(TIME_FILE)
+
+cleantime:
+	@$(RM) $(TIME_FILE)
+
 clean:
-	@rm -f $(TEST1_FILE) $(DIFF_FILE) $(LOG_FILE) $(ERR_FILE)
+	@$(RM) $(TEST1_FILE) $(DIFF_FILE) $(LOG_FILE) $(ERR_FILE) $(TIME_FILE)
 
 cleanall: clean
-	@rm -f $(TEST0_FILE)
+	@$(RM) $(TEST0_FILE)
 
-$(TEST0_FILE) $(TEST1_FILE):
-	@if test ! -s $(CMD_FILE); then echo "set command file: $(CMD_FILE)."; else $(CMD); fi
+$(TEST0_FILE) $(TEST1_FILE): $(CMD_FILE)
+	@-$(CMD)
 
 $(DIFF_FILE): $(TEST1_FILE)
-	@-diff -c $(TEST0_FILE) $(TEST1_FILE) >$@ 2>&1
+	@-$(DIFF) $(TEST0_FILE) $(TEST1_FILE) >$@ 2>&1
 
 $(LOG_FILE): $(DIFF_FILE)
-	@if test -s $(DESC_FILE); then cat $(DESC_FILE) >>$@; fi;
-	@if test ! -s $^; then echo "$(TEST): Test Success $(DATE)"  >>$@; else echo "$(TEST): Test Failure $(DATE)" >>$@; fi;
+	@$(DESC)
+	@$(REPORT_TEST)
+
+$(TIME_FILE): $(CMD_FILE)
+	@$(TIME) ./$(CMD_FILE) 1>/dev/null && $(CAT) $@
-- 
2.18.0