LoginSignup
1
0

More than 5 years have passed since last update.

cutterを使ってみよう

Posted at

動機

別の記事を書くのに必要だったので。
まずはとりあえず、記事を書くためにC用のユニットテストフレームワークを探していたら国産で見つけたのでトライしてみんとするなり。
作りたいものはCSVのパーサーです。

Step.1 インストール

公式ページ に書いてありますから・・・なお、私は
brew install cutter
で済ませました。

Step.2 テスト実行

今回のテスト対象は1行読み込み、「,」を\0に置き換え、それぞれ、先頭のポインタを保持する配列を作る関数を作ることです。

イメージ的にはこんな感じ

入力: "A,B,C"

作成するデータ:
データ: ['A', '\0', 'B', '\0', 'C', '\0']
ポインタ配列: array = [0, 2, 4]

こうすることでarray[2]とすることで"C"が取れるようになるわけです。

Step 2.0 構成

その前に構成を次のようにします。

-+-src
 +-test
 +-obj

Step.2.1 テストを書く

テスト対象はread_recordという関数です。
引数は順に

  1. 入力文字
  2. 配列
  3. 配列が収容できる最大のサイズ
  4. データ格納配列
  5. データ格納配列が収容できる最大のサイズ

です。

test/t_record_read.c
#include <cutter.h>
#include <string.h>
#include "record_read.h"

#define BUF_LEN 4096
void test_record_read(void) {
    char *test = "A,B,C";
    char *result[BUF_LEN];
    char result_store[BUF_LEN];

    csv_read_result ret = record_read(test, result, BUF_LEN, result_store, BUF_LEN);

    cut_assert_not_null(result);
    cut_assert_equal_int(ret, 0);
    cut_assert(strcmp(result[0], "A"));
    cut_assert(strcmp(result[1], "B"));
    cut_assert(strcmp(result[2], "C"));
}

さて、ここで私は詰まりました。チュートリアルにあるAutotoolの使い方を知らないからです。
勉強しなければならないのですが、とりあえず、コンパイルして・・・と力技で行くことにしました(最悪)。

Step 2.1 テスト対象関数の作成

とりあえず、ヘッダを作成します。

csv_read.h
#ifndef __CSV_READER_H__
#define __CSV_READER_H__
typedef enum csv_read_result {
    csv_read_normal = 0,
    csv_read_destination_is_not_enough = -1,
    csv_read_destination_is_null = -2,
    csv_read_array_is_null = -3,
    csv_read_array_is_not_enough = -4
} csv_read_result;

/**
 * @brief create string array from src by csv
 *
 * @param[in]   src input string
 * @param[out]  array output array of string
 * @param[in]   array_len length of array
 * @param[out]  dst store output array
 * @param[in]   len length of dst
 * @retval 0 normal end
 * @retval -1 not enough allocated to input to dst
 * @retval -2 dst is NULL
 */
csv_read_result record_read(char* src, char** array, int array_len, char* dst, int len);
#endif

えーっと、csv_read_resultはintと読み替えてください。なんか、書き方が変なんです。僕。
テスト対象コードも一緒に作っちゃいます。当然失敗する内容です。

record_read.c
#include <stdio.h>
#include <stdlib.h>
#include "record_read.h"

csv_read_result record_read(char* src, char** array, int array_len, char* dst, int len) {
    return csv_read_normal;
}

で、コンパイルします。

#compile objects
cc -c src/record_read.c -o obj/record_read.o

cc -shared -o librecord_read.so obj/record_read.o

#compile test
cc -shared -I /usr/local/include/cutter -lcutter -I src -L . -lrecord_read -o test/libt_record_read.so test/t_record_read.c

2.2 実行

で、実行。

 cutter test/

!
===============================================================================
Crash: test_record_read
===============================================================================


Finished in 0.533029 seconds (total: 0.532630 seconds)

1 test(s), 2 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
0% passed

は・・・はやい・・・
2個目のassertionで失敗しているので、いい感じかもしれません。ただ、クラッシュさせているのはよくないですよね・・・

2.3 修正

で、通るように修正です。

csv_reader.c
#include <stdio.h>
#include <stdlib.h>
#include "record_read.h"

csv_read_result record_read(char* src, char** array, int array_len, char* dst, int len) {
    int index = 0; //array index
    int i;
    if ( dst == NULL )  return csv_read_destination_is_null;
    if ( array == NULL ) return csv_read_array_is_null;

    array[0] = dst;
    index++;
    for( i = 0; i < len; i++ ) {
        if (src[i] == '\0') break;
        if (src[i] == ',') {
            dst[i] = '\0';
            // check array length is nough
            if ( index >= array_len ) {
                return csv_read_array_is_not_enough;
            }
            array[index] = dst + i;
            index++;
        }
        dst[i] = src[i];
    }
    if ( i == len ) {
        dst[i] = '\0';
        return csv_read_destination_is_not_enough;
    }
    return csv_read_normal;
}

再度コンパイルして実行。

$ sh first_compie_and_test.sh
.

Finished in 0.000625 seconds (total: 0.000122 seconds)

1 test(s), 5 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
100% passed

まずはOKですかね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0