Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ env:
CARGO_TERM_COLOR: always

jobs:
build-and-test:
lib-build-and-test:
name: Build & Test
runs-on: ${{ matrix.os }}
timeout-minutes: 30
Expand Down Expand Up @@ -56,10 +56,66 @@ jobs:
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

- name: Build release binary for extension tests (macOS ARM64 only)
if: matrix.target == 'aarch64-apple-darwin'
run: cargo build --release --target ${{ matrix.target }}

- name: Upload release binary for extension tests (macOS ARM64 only)
if: matrix.target == 'aarch64-apple-darwin'
uses: actions/upload-artifact@v4
with:
name: log2src-test-binary
path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
if-no-files-found: error

vscode-extension-test:
name: Test VS Code Extension
needs: [lib-build-and-test]
# Disabled: @vscode/test-electron can't launch the current VS Code release on macOS.
if: false
runs-on: macos-latest
timeout-minutes: 15

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Download log2src binary
uses: actions/download-artifact@v4
with:
name: log2src-test-binary
path: downloaded-binary

- name: Setup binary for VS Code extension
run: |
mkdir -p editors/code/bin/darwin-arm64
cp downloaded-binary/log2src editors/code/bin/darwin-arm64/
chmod +x editors/code/bin/darwin-arm64/log2src

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.8.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
cache-dependency-path: 'editors/code/pnpm-lock.yaml'

- name: Install Dependencies
working-directory: editors/code
run: pnpm install

- name: Run tests
working-directory: editors/code
run: pnpm run test

build-release:
name: Build Release
needs: [build-and-test]
needs: [lib-build-and-test]
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
runs-on: ${{ matrix.os }}
timeout-minutes: 30
Expand Down
1 change: 1 addition & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"displayName": "log2src",
"description": "A debugger driven by logs",
"version": "0.0.1",
"publisher": "ttiimm",
"author": {
"name": "Tim Likarish Ellis"
},
Expand Down
1 change: 1 addition & 0 deletions editors/code/src/debugAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface SourceRef {
lineNumber: number,
column: number,
name: string,
level: string,
}

interface ILaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
Expand Down
265 changes: 265 additions & 0 deletions editors/code/src/test/suite/debugAdapter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
import * as assert from 'assert';
import { DebugProtocol } from '@vscode/debugprotocol';

import { DebugSession, BinaryNotFoundError } from '../../debugAdapter';


suite('DebugAdapter Test Suite', () => {
let debugSession: DebugSession | undefined;
let originalPlatform: string;
let originalArch: string;

setup(() => {
originalPlatform = process.platform;
originalArch = process.arch;
});

teardown(() => {
Object.defineProperty(process, 'platform', {
value: originalPlatform,
configurable: true
});
Object.defineProperty(process, 'arch', {
value: originalArch,
configurable: true
});

if (debugSession) {
try {
(debugSession as any).dispose?.();
} catch (e) {
// Ignore
}
debugSession = undefined;
}
});

suite('Constructor Tests', () => {
test('Should create debug session with correct binary path for darwin-arm64', () => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'arm64',
configurable: true
});

debugSession = new DebugSession();

assert.ok(debugSession, 'Debug session should be created');
});

test('Should create debug session with correct binary path for linux-x64', () => {
Object.defineProperty(process, 'platform', {
value: 'linux',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'x64',
configurable: true
});

debugSession = new DebugSession();

assert.ok(debugSession, 'Debug session should be created');
});

test('Should create debug session with correct binary path for win32-x64', () => {
Object.defineProperty(process, 'platform', {
value: 'win32',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'x64',
configurable: true
});

debugSession = new DebugSession();

assert.ok(debugSession, 'Debug session should be created');
});

test('Should throw BinaryNotFoundError for unsupported platform', () => {
Object.defineProperty(process, 'platform', {
value: 'unsupported',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'unsupported',
configurable: true
});

assert.throws(() => {
new DebugSession();
}, BinaryNotFoundError, 'Should throw BinaryNotFoundError for unsupported platform');
});
});

suite('Initialize Request Tests', () => {
setup(() => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'arm64',
configurable: true
});
debugSession = new DebugSession();
});

test('Should handle initialize request correctly', () => {
const args: DebugProtocol.InitializeRequestArguments = {
clientID: 'test-client',
clientName: 'Test Client',
adapterID: 'log2src',
pathFormat: 'path'
};

const response: DebugProtocol.InitializeResponse = {
request_seq: 1,
success: true,
command: 'initialize',
seq: 1,
type: 'response',
body: {}
};

let capturedResponse: DebugProtocol.InitializeResponse | undefined;
const originalSendResponse = (debugSession as any).sendResponse.bind(debugSession);
(debugSession as any).sendResponse = (resp: any) => {
capturedResponse = resp;
};

let eventSent = false;
const originalSendEvent = (debugSession as any).sendEvent.bind(debugSession);
(debugSession as any).sendEvent = () => {
eventSent = true;
};

try {
(debugSession as any).initializeRequest(response, args);

assert.ok(capturedResponse, 'Response should be sent');
assert.ok(eventSent, 'Event should be sent');

assert.ok(capturedResponse!.body, 'Response should have body');
assert.strictEqual(capturedResponse!.body.supportsStepBack, true);
assert.strictEqual(capturedResponse!.body.supportTerminateDebuggee, true);
} finally {
(debugSession as any).sendResponse = originalSendResponse;
(debugSession as any).sendEvent = originalSendEvent;
}
});
});

suite('Breakpoint Tests', () => {
setup(() => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
configurable: true
});
Object.defineProperty(process, 'arch', {
value: 'arm64',
configurable: true
});
debugSession = new DebugSession();
});

test('Should set breakpoints correctly', () => {
const sourcePath = '/test/source/file.log';
const args: DebugProtocol.SetBreakpointsArguments = {
source: { path: sourcePath },
breakpoints: [
{ line: 10 },
{ line: 20 },
{ line: 30 }
]
};

const response: DebugProtocol.SetBreakpointsResponse = {
request_seq: 1,
success: true,
command: 'setBreakpoints',
seq: 1,
type: 'response',
body: { breakpoints: [] }
};

let capturedResponse: DebugProtocol.SetBreakpointsResponse | undefined;
const originalSendResponse = (debugSession as any).sendResponse.bind(debugSession);
(debugSession as any).sendResponse = (resp: any) => {
capturedResponse = resp;
};

let eventSent = false;
const originalSendEvent = (debugSession as any).sendEvent.bind(debugSession);
(debugSession as any).sendEvent = () => {
eventSent = true;
};

try {
(debugSession as any).setBreakPointsRequest(response, args);

assert.ok(capturedResponse, 'Response should be sent');

assert.ok(capturedResponse!.body, 'Response should have body');
assert.ok(capturedResponse!.body.breakpoints, 'Response should have breakpoints');
assert.strictEqual(capturedResponse!.body.breakpoints.length, 3, 'Should have 3 breakpoints');

capturedResponse!.body.breakpoints.forEach((bp, index) => {
assert.strictEqual(bp.line, args.breakpoints![index].line, `Breakpoint ${index} should have correct line`);
});

assert.ok(eventSent, 'Should send stopped event');
} finally {
(debugSession as any).sendResponse = originalSendResponse;
(debugSession as any).sendEvent = originalSendEvent;
}
});

test('Should handle empty breakpoints array', () => {
const sourcePath = '/test/source/file.log';
const args: DebugProtocol.SetBreakpointsArguments = {
source: { path: sourcePath },
breakpoints: []
};

const response: DebugProtocol.SetBreakpointsResponse = {
request_seq: 1,
success: true,
command: 'setBreakpoints',
seq: 1,
type: 'response',
body: { breakpoints: [] }
};

let capturedResponse: DebugProtocol.SetBreakpointsResponse | undefined;
let eventSent = false;

const originalSendResponse = (debugSession as any).sendResponse.bind(debugSession);
(debugSession as any).sendResponse = (resp: any) => {
capturedResponse = resp;
};

const originalSendEvent = (debugSession as any).sendEvent.bind(debugSession);
(debugSession as any).sendEvent = () => {
eventSent = true;
};

try {
(debugSession as any).setBreakPointsRequest(response, args);

assert.ok(capturedResponse, 'Response should be sent');
assert.ok(capturedResponse!.body, 'Response should have body');
assert.ok(capturedResponse!.body.breakpoints, 'Response should have breakpoints array');
assert.strictEqual(capturedResponse!.body.breakpoints.length, 0, 'Should have no breakpoints');
assert.strictEqual(eventSent, false, 'Should not send stopped event for empty breakpoints');
} finally {
(debugSession as any).sendResponse = originalSendResponse;
(debugSession as any).sendEvent = originalSendEvent;
}
});
});
});
21 changes: 18 additions & 3 deletions editors/code/src/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,23 @@ import * as vscode from 'vscode';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');

test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
test('Extension should be present', () => {
assert.ok(vscode.extensions.getExtension('ttiimm.log2src-ext'));
});

test('Extension should activate', async () => {
const ext = vscode.extensions.getExtension('ttiimm.log2src-ext');
assert.ok(ext);
await ext!.activate();
assert.strictEqual(ext!.isActive, true);
});

test('Should register log2src debug type', async () => {
// Ensure extension is activated
const ext = vscode.extensions.getExtension('ttiimm.log2src-ext');
await ext?.activate();

// Verify the extension activated successfully
assert.ok(ext?.isActive, 'Extension should be active');
});
});
Loading