Get the FREE Ultimate OpenClaw Setup Guide →

obs-testing-guide

npx machina-cli add skill UtakataKyosui/C2Lab/obs-testing-guide --openclaw
Files (1)
SKILL.md
6.5 KB

OBS プラグインのテスト・デバッグガイド

テスト環境のセットアップ

必要なツール

# Linux(Ubuntu/Debian)
sudo apt install \
    obs-studio \
    gdb \
    valgrind \
    libasan8 \
    cmake \
    ninja-build

# macOS
brew install obs lldb cmake ninja

# Rust プロジェクトの場合
rustup component add rust-src
cargo install cargo-expand  # マクロ展開確認

デバッグビルドの作成

# C/C++ プロジェクト
cmake -B build-debug \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build-debug

# Rust プロジェクト
cargo build  # debug ビルド(デフォルト)

blog() でのログ出力

OBS のログシステムを使った基本的なデバッグ手法:

// C/C++: obs-module.h をインクルード
blog(LOG_INFO,    "width=%d, height=%d", width, height);
blog(LOG_WARNING, "設定ファイルが見つかりません");
blog(LOG_ERROR,   "テクスチャ生成失敗");
blog(LOG_DEBUG,   "コールバック呼び出し: %s", __func__);
// Rust: FFI 経由でログ出力
extern "C" {
    fn blog(level: i32, format: *const u8, ...);
}

macro_rules! obs_log {
    ($level:expr, $msg:literal) => {
        unsafe { blog($level, concat!($msg, "\0").as_ptr()) }
    };
}

obs_log!(300, "プラグインが初期化されました");

ログの確認:

# Linux
tail -f ~/.config/obs-studio/logs/*.txt

# OBS 起動時の詳細ログ
obs --verbose 2>&1 | grep "my-plugin"

C/C++ テストパターン

OBS 依存部分をモックしてユニットテストを実施する。

カスタムテストハーネス

// test/test_utils.h
#pragma once
#include <stdio.h>
#include <stdlib.h>

static int test_pass_count = 0;
static int test_fail_count = 0;

#define ASSERT_EQ(a, b) do { \
    if ((a) == (b)) { \
        test_pass_count++; \
        printf("  PASS: " #a " == " #b "\n"); \
    } else { \
        test_fail_count++; \
        printf("  FAIL: " #a " == " #b " (got %d vs %d)\n", (int)(a), (int)(b)); \
    } \
} while(0)

#define ASSERT_NOT_NULL(p) do { \
    if ((p) != NULL) { \
        test_pass_count++; \
    } else { \
        test_fail_count++; \
        printf("  FAIL: " #p " should not be NULL\n"); \
    } \
} while(0)

#define RUN_TEST(fn) do { \
    printf("Running: " #fn "\n"); \
    fn(); \
} while(0)

#define PRINT_RESULTS() do { \
    printf("\n結果: %d passed, %d failed\n", test_pass_count, test_fail_count); \
    exit(test_fail_count > 0 ? 1 : 0); \
} while(0)

詳細: references/test-patterns.md


Rust テストパターン

Rust の #[cfg(test)] を使ってビジネスロジックをテスト。

ロジック層と FFI 層の分離

src/
├── lib.rs          # FFI エントリポイント(obs_module_load等)
├── source.rs       # FFI ラッパー(unsafe extern "C" fn)
└── logic/
    ├── mod.rs      # ロジック層(OBS非依存・テスト可能)
    └── processing.rs
// src/logic/processing.rs - OBS 非依存のビジネスロジック
pub struct FrameProcessor {
    pub width: u32,
    pub height: u32,
    pub intensity: f32,
}

impl FrameProcessor {
    pub fn new(width: u32, height: u32) -> Self {
        Self { width, height, intensity: 1.0 }
    }

    pub fn apply_grayscale(&self, pixel: [u8; 4]) -> [u8; 4] {
        let gray = (pixel[0] as f32 * 0.299
                  + pixel[1] as f32 * 0.587
                  + pixel[2] as f32 * 0.114) as u8;
        [gray, gray, gray, pixel[3]]
    }

    pub fn pixel_count(&self) -> u64 {
        self.width as u64 * self.height as u64
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new_processor() {
        let proc = FrameProcessor::new(1920, 1080);
        assert_eq!(proc.width, 1920);
        assert_eq!(proc.height, 1080);
        assert_eq!(proc.intensity, 1.0);
    }

    #[test]
    fn test_grayscale_red_pixel() {
        let proc = FrameProcessor::new(100, 100);
        let red = [255, 0, 0, 255];
        let result = proc.apply_grayscale(red);
        // R=255 の場合: gray = 255 * 0.299 ≈ 76
        assert_eq!(result[0], result[1]);
        assert_eq!(result[1], result[2]);
        assert_eq!(result[3], 255); // アルファは保持
    }

    #[test]
    fn test_pixel_count() {
        let proc = FrameProcessor::new(1920, 1080);
        assert_eq!(proc.pixel_count(), 1920 * 1080);
    }
}
# テスト実行
cargo test

# 特定のテストのみ
cargo test test_grayscale

# 詳細出力
cargo test -- --nocapture

詳細: references/rust-testing.md


GDB/LLDB デバッグセッション

# GDB(Linux)
gdb --args obs --scene test-scene
(gdb) break my_source_create
(gdb) run
# ブレークポイントで停止したら
(gdb) info locals  # ローカル変数表示
(gdb) bt           # バックトレース
(gdb) p data->width  # 変数の値確認

# LLDB(macOS)
lldb -- obs
(lldb) breakpoint set --name my_source_create
(lldb) run
(lldb) frame variable

Valgrind / AddressSanitizer

Valgrind(メモリリーク)

valgrind --leak-check=full \
         --track-origins=yes \
         obs 2>&1 | grep "my-plugin"

AddressSanitizer(ASan)

# CMake
cmake -B build-asan \
    -DCMAKE_C_FLAGS="-fsanitize=address -g" \
    -DCMAKE_BUILD_TYPE=Debug

# Rust
RUSTFLAGS="-Z sanitizer=address" cargo +nightly test \
    --target x86_64-unknown-linux-gnu

OBS 内統合テスト

# OBS にテスト用シーンを用意して起動
obs --scene obs-plugin-test.json --verbose

# プラグインのロード確認
grep "my-plugin" ~/.config/obs-studio/logs/*.txt

# 特定シーンで動作確認後、OBS を終了
obs --scene test.json --minimize-to-tray

参考ファイル

  • references/test-patterns.md - C 言語テストの実装例(モックOBS API)
  • references/rust-testing.md - Rust テスト戦略(cargo test、FFIモック、ロジック分離)

Source

git clone https://github.com/UtakataKyosui/C2Lab/blob/main/plugins/obs-plugin-dev/skills/obs-testing-guide/SKILL.mdView on GitHub

Overview

OBS Studioプラグインのテストとデバッグを体系的に解説します。C/C++のユニットテスト、Rustの cargo test、gdb/lldbデバッグ、Valgrindのメモリ検査、blog()ログ出力、AddressSanitizerの使い方までをカバーします。

How This Skill Works

環境セットアップからデバッグビルド作成、テスト実行までの一連の手順を説明します。C/C++とRustのテストパターン、ログ出力の実装例、各種ツールの活用方法を具体的なコード例とともに紹介します。

When to Use It

  • C/C++ プラグインのユニットテストを実施したいとき
  • Rust 部分を cargo test で検証したいとき
  • バグを再現して gdb/lldb でデバッグしたいとき
  • メモリ問題を検出するため Valgrind や AddressSanitizer を使いたいとき
  • 実行時の挙動を blog ログで追跡して検証したいとき

Quick Start

  1. Step 1: OS に必要なツールをインストールする(Linux は apt、macOS は brew を使用)
  2. Step 2: デバッグビルドを作成する。C/C++ は cmake -B build-debug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON など、Rust は cargo build を実行
  3. Step 3: blog ログを有効化してログを確認する。OBS のログを tail や --verbose 出力で検証する

Best Practices

  • OBS依存部をモックしてユニットテストを実施する
  • デバッグビルドを cmake で C/C++、Rust は cargo build で作成する
  • ブログログの出力を blog で統一して実行時挙動を検証する
  • Valgrind と AddressSanitizer でメモリ関連の問題を検出する
  • テストとログの結果を継続的にレビューして品質を改善する

Example Use Cases

  • C/C++ のカスタムテストハーネスを使い ASSERT_EQ や ASSERT_NOT_NULL、RUN_TEST、PRINT_RESULTS のマクロでユニットテストを実行する
  • Rust の FrameProcessor を対象に #[cfg(test)] テストを作成して新機能を検証する
  • Rust 側の FFI 層とロジック層を分離してテストする構成を採用する
  • デバッグビルド作成の具体コマンド例として cmake -B build-debug ... を使う
  • OBS ログファイルの確認方法として tail -f ~/.config/obs-studio/logs/*.txt や obs --verbose の活用を実践する

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers