社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

なぜ、sudo rm でワイルドカード指定できないのか

sudo rm でワイルドカード指定したのに動かない。

$ sudo rm /var/log/elasticsearch/elasticsearch.*.log
rm: cannot remove `/var/log/elasticsearch/elasticsearch*log': No such file or directory

ワイルドカード拡張は、rmではなくシェルによって行われる。
また、シェルにはsudo権限はなく、rmのみにある。
したがって、シェルには/var/log/elasticsearch/を読み取る権限がないため
展開は行われず、rmはファイル(ワイルドカードではない)/var/log/elasticsearch/*(存在しない)を削除しようとする。

これを回避するには、rmを実行するsudo権限を持つシェルが必要となる。

sudo sh -c 'rm /var/log/elasticsearch/elasticsearch*.log'

JUnit DataPoint によるテストパラメータ定義

例えば、文字列を引数に取るメソッドをテストするにあたり、色んな文字列でテストしたい場合。
テストする文字列ごとにテストケースを作成するのは大変。
DataPoint を使うことで、それらのパラメータを配列で管理することができ、文字列一つずつを一つのテストケース内で自動的に適用しながらテストすることが可能となる。
※そのメソッドの期待値が引数に依存せずに同一であれば評価しやすいが、もし異なる場合、それぞれの引数に対する期待値を別途定義が必要

@RunWith(Theories.class)
public class DataPointSampleTest2 {
	@DataPoints	// for multi test data
	public static String[] DATA_PARAM = { "JAPAN", "JAPANESE" };
	
	private static int index = 0;
	
	@Theory
	public void test(String param) {
		System.out.println("test param=" + param);
		assertThat(param, is(DATA_PARAM[index++]));
	}
}

このテストでは、引数param として、”JAPAN” と "JAPANESE" が順番にテストされる。
コンソールでの標準出力。

test param=JAPAN
test param=JAPANESE

Python CUIで迷路生成(3)

スタートとゴールの場所を指定するところまで。
set_start_goal
ランダムに座標を指定し、そこが通路ならスタート”S”、またはゴール”G” をそこに設置する。

import sys
import random

class Maze():
    PATH = 0
    WALL = 1
    START = 2
    GOAL = 3

    def __init__(self, height, width):
        self.maze = []
        self.width = width
        self.height = height
        if (self.width % 2) == 0:
            self.width += 1
        if (self.height % 2) == 0:
            self.height += 1
    
    def set_outer_wall(self):
        for y in range(0, self.height):
            row = []
            for x in range(0, self.width):
                if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1):
                    cell = self.WALL
                else:
                    cell = self.PATH
                row.append(cell)
            self.maze.append(row)

    def set_inner_wall(self):
        for x in range(2, self.width-1, 2):
            for y in range(2, self.height-1, 2):
                self.maze[y][x] = self.WALL
                while True:
                    wall_x = x
                    wall_y = y
                    if y == 2:
                        direction = random.randrange(0, 4)
                    else:
                        direction = random.randrange(0, 3)

                    if direction == 0:
                        wall_x += 1
                    elif direction == 1:
                        wall_y += 1
                    elif direction == 2:
                        wall_x -= 1
                    else:
                        wall_y -= 1
                    if self.maze[wall_y][wall_x] != self.WALL:
                        self.maze[wall_y][wall_x] = self.WALL
                        break

    def set_start_goal(self):
        # set start
        while True:
            s_x = random.randrange(1, self.width-1)
            s_y = random.randrange(1, self.height-1)
            if self.maze[s_y][s_x] == self.PATH:
                self.maze[s_y][s_x] = self.START
                break
        # set goal
        while True:
            g_x = random.randrange(1, self.width-1)
            g_y = random.randrange(1, self.height-1)
            if self.maze[g_y][g_x] == self.PATH:
                self.maze[g_y][g_x] = self.GOAL
                break

    def print_maze(self):
        for row in self.maze:
            for cell in row:
                if cell == self.PATH:
                    print(' ', end='')
                elif cell == self.WALL:
                    print('#', end='')
                elif cell == self.START:
                    print('S', end='')
                elif cell == self.GOAL:
                    print('G', end='')
            print()

args = sys.argv
maze = Maze(int(args[1]), int(args[2]))
maze.set_outer_wall()
maze.set_inner_wall()
maze.set_start_goal()
maze.print_maze()

出力例

$ python create_maze.py 10 20
#####################
# #       #     #   #
# ### ##### # ### ###
#           #       #
# ##### # # ##### ###
#   #   # #     #  S#
# ##### ####### #####
# #         #       #
# # ##### ### # # ###
# #  G#   #   # #   #
#####################

JUnit Enclosed によるテストケースのグループ化

既に存在しているテストクラスに新しいテストケースを追加するとき、どの位置に入れようか迷うときがあります。
出来れば、後で見たときに分かりやすい位置に入れたいですが、そもそも整理されていなければそれも難しいです。そこで Enclosedを使うことで、テストケースのグループ化が可能です。

@RunWith(Enclosed.class)
public class RunWithTest {
	public static class TestForNumber {
	    @Test
            public void additionTest() {
                int actual = 1 + 2;
                assertThat(actual, is(3)); 
            }
		
	    @Test
	    public void subtractionTest() {
	        int actual = 1 - 2;
                assertThat(actual, is(-1)); 
	    }
	}
	
	public static class TestForCharacter {
	    @Test
            public void additionTest() {
                String actual = "a" + "b";
                assertThat(actual, is("ab")); 
            }
		
	    @Test
	    public void replaceTest() {
	        String actual = "a".replace("a", "b");
                assertThat(actual, is("b")); 
	    }
	}
}

どのような観点でグループ化するか迷いところですが、いくつかヒントはありそうです。

  • 共通のデータで分ける
  • 共通の状態で分ける
  • コンストラクタのテストを分ける など

テスト結果も以下のようにグループ化されて表示されます。
f:id:blueskyarea:20190717233754p:plain

Python CUIで迷路生成(2)

内壁を生成するところまで。
棒倒し法により生成するが、その手順は
1. 迷路全体を構成する2次元配列を、幅高さ5以上の奇数で生成する
2. 迷路の外周を壁とし、それ以外を通路とする
3. 外周の内側に基準となる壁(棒)を1セルおき(x, y ともに偶数の座標)に配置する
4. 内側の壁(棒)を走査し、ランダムな方向に倒して壁とする
※ただし以下に当てはまる方向以外に倒す

  • 1行目の内側の壁以外では上方向に倒してはいけない
  • すでに棒が倒され壁になっている場合、その方向には倒してはいけない
import sys
import random

class Maze():
    PATH = 0
    WALL = 1

    def __init__(self, height, width):
        self.maze = []
        self.width = width
        self.height = height
        if (self.width % 2) == 0:
            self.width += 1
        if (self.height % 2) == 0:
            self.height += 1
    
    def set_outer_wall(self):
        for y in range(0, self.height):
            row = []
            for x in range(0, self.width):
                if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1):
                    cell = self.WALL
                else:
                    cell = self.PATH
                row.append(cell)
            self.maze.append(row)
        return self.maze

    def set_inner_wall(self):
        for x in range(2, self.width-1, 2):
            for y in range(2, self.height-1, 2):
                self.maze[y][x] = self.WALL
                while True:
                    wall_x = x
                    wall_y = y
                    if y == 2:
                        direction = random.randrange(0, 4)
                    else:
                        direction = random.randrange(0, 3)

                    if direction == 0:
                        wall_x += 1
                    elif direction == 1:
                        wall_y += 1
                    elif direction == 2:
                        wall_x -= 1
                    else:
                        wall_y -= 1
                    if self.maze[wall_y][wall_x] != self.WALL:
                        self.maze[wall_y][wall_x] = self.WALL
                        break
        return self.maze

    def print_maze(self):
        for row in self.maze:
            for cell in row:
                if cell == self.PATH:
                    print(' ', end='')
                elif cell == self.WALL:
                    print('#', end='')
            print()

args = sys.argv
maze = Maze(int(args[1]), int(args[2]))
maze.set_outer_wall()
maze.set_inner_wall()
maze.print_maze()

出力例

$ python create_maze.py 10 20
#####################
# #   #         # # #
# # # # # # ### # # #
#   #   # # #       #
# ##### ### # ##### #
#   #     # #     # #
# ##### ######### # #
#   #     #       # #
### # ### ##### ### #
#   #   #     #   # #
#####################

Java 例外(Exception) テスト

例外(Exception)のテストの書き方でよく知られているもので、Ruleアノテーションを用いた ExpectedException を使う方法があります。
例外のメッセージまで評価してくれるのがいいですね。

public class RuleTest {
	@Rule
	public ExpectedException expectedException = ExpectedException.none();

	@Test
	public void testThrowException() {
		expectedException.expect(RuntimeException.class);
		expectedException.expectMessage("Rule test");
		throw new RuntimeException("Rule test");
	}
}

Python CUIで迷路生成(1)

外壁を生成するところまでのステップ。
__init__
1. Maze(迷路) クラスを生成し、maze, width, height の変数を定義する
※第一引数で縦のサイズ(height)、第二引数で横のサイズ(width)を与える

set_outer_wall
2. row という配列にそのセルが壁なのか、通路なのかを格納していく
3. maze に1行ずつ(row) を格納していく

print_maze
4. maze に格納されている row を一つずつ取り出し、さらにセルを一つずつ取り出し、画面出力(壁か通路)させる

import sys
import random

class Maze():
    PATH = 0
    WALL = 1

    def __init__(self, height, width):
        self.maze = []
        self.width = width
        self.height = height
    
    def set_outer_wall(self):
        for y in range(0, self.height):
            row = []
            for x in range(0, self.width):
                if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1):
                    cell = self.WALL
                else:
                    cell = self.PATH
                row.append(cell)
            self.maze.append(row)
        return self.maze

    def print_maze(self):
        for row in self.maze:
            for cell in row:
                if cell == self.PATH:
                    print(' ', end='')
                elif cell == self.WALL:
                    print('#', end='')
            print()

args = sys.argv
maze = Maze(int(args[1]), int(args[2]))
maze.set_outer_wall()
maze.print_maze()

出力例

python create_maze.py 10 20
####################
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
####################