un-inception/tests/test_un_pl.pl
Russell Ballestrini 2b35819393 Initial commit: 42 UN CLI implementations
Unsandbox CLI implementations in 42 programming languages for the
permacomputer project. Public domain software for code execution
across all ecosystems.

Languages: Python, JavaScript, Ruby, Go, Rust, C, C++, Java, Kotlin,
C#, F#, Haskell, OCaml, Clojure, Scheme, Common Lisp, Erlang, Elixir,
D, Nim, Zig, V, Dart, Groovy, Scala, Julia, R, Crystal, Fortran,
COBOL, Prolog, Forth, Tcl, Raku, Lua, PHP, Perl, Bash, TypeScript,
Objective-C, PowerShell, AWK

Includes test suites and service lifecycle tests.
2025-12-23 09:57:08 -05:00

219 lines
6.5 KiB
Perl
Executable file

#!/usr/bin/env perl
# Test suite for UN CLI Perl implementation (un.pl)
# Tests extension detection, API calls, and end-to-end functionality
use strict;
use warnings;
use File::Basename;
use File::Spec;
use JSON::PP;
use LWP::UserAgent;
use HTTP::Request;
# Test configuration
my $script_dir = dirname(__FILE__);
my $UN_SCRIPT = File::Spec->catfile($script_dir, '..', 'un.pl');
my $FIB_PY = File::Spec->catfile($script_dir, '..', '..', 'test', 'fib.py');
package TestResults;
sub new {
my $class = shift;
my $self = {
passed => 0,
failed => 0,
skipped => 0,
};
return bless $self, $class;
}
sub pass_test {
my ($self, $name) = @_;
print "PASS: $name\n";
$self->{passed}++;
}
sub fail_test {
my ($self, $name, $error) = @_;
print "FAIL: $name - $error\n";
$self->{failed}++;
}
sub skip_test {
my ($self, $name, $reason) = @_;
print "SKIP: $name - $reason\n";
$self->{skipped}++;
}
package main;
my $results = TestResults->new();
# Extension map for testing
my %EXTENSION_MAP = (
'.py' => 'python', '.js' => 'javascript', '.ts' => 'typescript', '.rb' => 'ruby',
'.php' => 'php', '.pl' => 'perl', '.lua' => 'lua', '.sh' => 'bash',
'.go' => 'go', '.rs' => 'rust', '.c' => 'c', '.cpp' => 'cpp', '.cc' => 'cpp',
'.java' => 'java', '.kt' => 'kotlin', '.cs' => 'csharp', '.hs' => 'haskell',
'.ml' => 'ocaml', '.clj' => 'clojure', '.ex' => 'elixir', '.erl' => 'erlang',
'.swift' => 'swift', '.r' => 'r', '.jl' => 'julia', '.dart' => 'dart',
'.scala' => 'scala', '.groovy' => 'groovy', '.nim' => 'nim', '.cr' => 'crystal',
'.v' => 'vlang', '.zig' => 'zig', '.fs' => 'fsharp', '.vb' => 'vb',
'.pas' => 'pascal', '.f90' => 'fortran', '.asm' => 'assembly', '.d' => 'd',
'.rkt' => 'racket', '.scm' => 'scheme', '.lisp' => 'common_lisp',
'.sol' => 'solidity', '.cob' => 'cobol', '.ada' => 'ada', '.tcl' => 'tcl',
);
sub detect_language {
my ($filename) = @_;
my ($name, $dir, $ext) = fileparse($filename, qr/\.[^.]*/);
return $EXTENSION_MAP{lc($ext)};
}
# Test 1: Extension detection for Python
eval {
my $lang = detect_language('test.py');
if ($lang eq 'python') {
$results->pass_test('Extension detection: .py -> python');
} else {
$results->fail_test('Extension detection: .py -> python', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .py -> python', $@);
}
# Test 2: Extension detection for JavaScript
eval {
my $lang = detect_language('test.js');
if ($lang eq 'javascript') {
$results->pass_test('Extension detection: .js -> javascript');
} else {
$results->fail_test('Extension detection: .js -> javascript', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .js -> javascript', $@);
}
# Test 3: Extension detection for Ruby
eval {
my $lang = detect_language('test.rb');
if ($lang eq 'ruby') {
$results->pass_test('Extension detection: .rb -> ruby');
} else {
$results->fail_test('Extension detection: .rb -> ruby', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .rb -> ruby', $@);
}
# Test 4: Extension detection for Go
eval {
my $lang = detect_language('test.go');
if ($lang eq 'go') {
$results->pass_test('Extension detection: .go -> go');
} else {
$results->fail_test('Extension detection: .go -> go', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .go -> go', $@);
}
# Test 5: Extension detection for Rust
eval {
my $lang = detect_language('test.rs');
if ($lang eq 'rust') {
$results->pass_test('Extension detection: .rs -> rust');
} else {
$results->fail_test('Extension detection: .rs -> rust', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .rs -> rust', $@);
}
# Test 6: Extension detection for unknown extension
eval {
my $lang = detect_language('test.unknown');
if (!defined $lang) {
$results->pass_test('Extension detection: .unknown -> undef');
} else {
$results->fail_test('Extension detection: .unknown -> undef', "Got $lang");
}
};
if ($@) {
$results->fail_test('Extension detection: .unknown -> undef', $@);
}
# Test 7: API call test (requires UNSANDBOX_API_KEY)
if (!$ENV{'UNSANDBOX_API_KEY'}) {
$results->skip_test('API call test', 'UNSANDBOX_API_KEY not set');
} else {
eval {
my $payload = encode_json({
language => 'python',
code => 'print("Hello from API")'
});
my $ua = LWP::UserAgent->new();
my $request = HTTP::Request->new(POST => 'https://api.unsandbox.com/execute');
$request->header('Authorization' => "Bearer $ENV{'UNSANDBOX_API_KEY'}");
$request->header('Content-Type' => 'application/json');
$request->content($payload);
my $response = $ua->request($request);
if ($response->is_success) {
my $result = decode_json($response->content);
if ($result->{stdout} && $result->{stdout} =~ /Hello from API/) {
$results->pass_test('API call test');
} else {
$results->fail_test('API call test', "Unexpected result: " . encode_json($result));
}
} else {
$results->fail_test('API call test', "HTTP " . $response->code . ": " . $response->content);
}
};
if ($@) {
$results->fail_test('API call test', $@);
}
}
# Test 8: End-to-end test with fib.py
if (!$ENV{'UNSANDBOX_API_KEY'}) {
$results->skip_test('End-to-end fib.py test', 'UNSANDBOX_API_KEY not set');
} elsif (!-e $FIB_PY) {
$results->skip_test('End-to-end fib.py test', "fib.py not found at $FIB_PY");
} else {
eval {
my $output = `$UN_SCRIPT $FIB_PY 2>&1`;
my $exit_code = $? >> 8;
if ($output =~ /fib\(10\) = 55/) {
$results->pass_test('End-to-end fib.py test');
} else {
my $preview = substr($output, 0, 200);
$results->fail_test('End-to-end fib.py test',
"Expected 'fib(10) = 55' in output, got: $preview");
}
};
if ($@) {
$results->fail_test('End-to-end fib.py test', $@);
}
}
# Print summary
print "\n" . "=" x 50 . "\n";
print "Test Summary:\n";
print " PASSED: $results->{passed}\n";
print " FAILED: $results->{failed}\n";
print " SKIPPED: $results->{skipped}\n";
my $total = $results->{passed} + $results->{failed} + $results->{skipped};
print " TOTAL: $total\n";
print "=" x 50 . "\n";
# Exit with appropriate code
exit($results->{failed} == 0 ? 0 : 1);