"""Exercise the actual C block writer and application integration on both OSes.""" from dataclasses import replace import json import os from pathlib import Path import shutil import struct import subprocess import sys import tempfile import unittest from unittest.mock import patch from app.simulation.native_codegen import build as builder, result_storage, runner from app.simulation.native_codegen.runner import execute_native from app.simulation.native_codegen.compiler import compile_native_program from app.simulation.config import SolveIVPConfig from tests.test_native_catalog import Circuit ROOT = Path(__file__).resolve().parents[1] HARNESS = r''' #include "runtime.h" #include #include static int evaluations=0; int model_eval(double t,const double *y,double *dy,double *w) { (void)t; (void)dy; evaluations++;w[0]=y[0];w[1]=y[1];return 1; } int main(int argc,char **argv) { if(argc!=4) return 64; NativeRun r={0};r.sample_path=argv[1];r.output_blocks_path=argv[2]; for(int i=0;i<10003;i++) { double y[2]={(double)i,-0.0}; if(!native_samples_append(&r,i,y)) return 2; /* Replace the last row while the four-row buffer is full. */ if(i%4==3) {y[0]+=.5;if(!native_samples_append(&r,i,y)) return 3;} if(r.buffered>4 || r.capacity!=4 || evaluations) return 4; } if(!native_samples_flush(&r) || !native_samples_outputs(&r)) return 5; FILE *f=fopen(argv[3],"wb");if(!f) return 6; fputs("[",f); for(int j=0;j<3;j++) { if(j) fputc(',',f); if(!native_samples_json(&r,f,j)) return 7; } fputs("]",f); if(fclose(f) || fclose(r.sample_file) || fclose(r.output_file)) return 8; free(r.times);free(r.states); printf("%zu %d\n",r.count,evaluations);return 0; } ''' class NativeSampleBufferTests(unittest.TestCase): def test_bounded_buffer_same_time_replacement_and_exact_output_bits(self): with tempfile.TemporaryDirectory(prefix='sample buffer ') as temporary: root = Path(temporary) compiler = os.environ.get('SIMULATION_NATIVE_CC') or shutil.which('gcc') if not compiler: if os.environ.get('SIMULATION_NATIVE_REQUIRE_TOOLCHAIN'): self.fail('C compiler is required') self.skipTest('C compiler not available') (root / 'model.h').write_text('#define NSTATES 2\n#define NOUTPUTS 2\n' 'int model_eval(double,const double*,double*,double*);\n') (root / 'test.c').write_text(HARNESS) executable = root / ('test.exe' if os.name == 'nt' else 'test') flags = ['-std=c11', '-O2', '-Wall', '-Wextra', '-Werror', '-DNATIVE_SAMPLE_BUFFER_BYTES=96', '-D_POSIX_C_SOURCE=200809L'] if os.name == 'nt': flags += ['-D__USE_MINGW_ANSI_STDIO=1'] builder._command([compiler, *flags, '-I', str(root), '-I', str(ROOT / 'native/include'), str(root / 'test.c'), str(ROOT / 'native/runtime/sample_storage.c'), str(ROOT / 'native/runtime/json_numbers.c'), str(ROOT / 'native/encoding/ryu/d2s.c'), '-o', str(executable)], log=[]) result = subprocess.run([str(executable), str(root / 'states.bin'), str(root / 'outputs.bin'), str(root / 'result.json')], capture_output=True, text=True, timeout=30) self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(result.stdout.strip(), '10003 10003') values = json.loads((root / 'result.json').read_bytes()) self.assertEqual(values[0], list(range(10003))) self.assertEqual(values[1], [i + (.5 if i % 4 == 3 else 0) for i in range(10003)]) self.assertTrue(all(struct.pack('