VariableSpec includes var name
This commit is contained in:
parent
2973dfd3ff
commit
52590cd2fb
7 changed files with 94 additions and 339 deletions
|
|
@ -29,9 +29,8 @@ The file is a json array of formulas.
|
|||
"magnitude" : "Force"
|
||||
}
|
||||
},
|
||||
"d4rt_code":{
|
||||
"return m*a;"
|
||||
}
|
||||
"d4rt_code": "return m*a;"
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:pruebas_d4rt/pruebas_d4rt.dart' as pruebas_d4rt;
|
||||
import 'package:d4rt_formulas/d4rt_formulas.dart' as pruebas_d4rt;
|
||||
import 'package:d4rt/d4rt.dart';
|
||||
|
||||
void main() {
|
||||
|
|
|
|||
|
|
@ -17,13 +17,11 @@ void main() {
|
|||
print('1. Newton\'s Second Law of Motion');
|
||||
final newtonFormula = Formula(
|
||||
name: "Newton's Second Law",
|
||||
input: {
|
||||
'm': VariableSpec(magnitude: 'mass'),
|
||||
'a': VariableSpec(magnitude: 'acceleration'),
|
||||
},
|
||||
output: {
|
||||
'F': VariableSpec(magnitude: 'force'),
|
||||
},
|
||||
input: [
|
||||
VariableSpec(name: 'm', magnitude: 'mass'),
|
||||
VariableSpec(name: 'a', magnitude: 'acceleration'),
|
||||
],
|
||||
output: VariableSpec(name: 'F', magnitude: 'force'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return m * a;
|
||||
|
|
@ -52,14 +50,12 @@ void main() {
|
|||
print('2. Quadratic Formula Discriminant (Δ = b² - 4ac)');
|
||||
final discriminantFormula = Formula(
|
||||
name: 'Quadratic Discriminant',
|
||||
input: {
|
||||
'a': VariableSpec(magnitude: 'coefficient'),
|
||||
'b': VariableSpec(magnitude: 'coefficient'),
|
||||
'c': VariableSpec(magnitude: 'coefficient'),
|
||||
},
|
||||
output: {
|
||||
'discriminant': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
input: [
|
||||
VariableSpec(name: 'a', magnitude: 'coefficient'),
|
||||
VariableSpec(name: 'b', magnitude: 'coefficient'),
|
||||
VariableSpec(name: 'c', magnitude: 'coefficient'),
|
||||
],
|
||||
output : VariableSpec(name: 'discriminant', magnitude: 'scalar'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return b * b - 4 * a * c;
|
||||
|
|
@ -95,12 +91,11 @@ void main() {
|
|||
print('3. Circle Area (A = π * r²)');
|
||||
final circleAreaFormula = Formula(
|
||||
name: 'Circle Area',
|
||||
input: {
|
||||
'r': VariableSpec(magnitude: 'length'),
|
||||
},
|
||||
output: {
|
||||
'A': VariableSpec(magnitude: 'area'),
|
||||
},
|
||||
input: [
|
||||
VariableSpec(name: 'r', magnitude: 'length'),
|
||||
],
|
||||
output: VariableSpec(name: 'A', magnitude: 'area'),
|
||||
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
var pi = 3.14159265359;
|
||||
|
|
@ -141,15 +136,13 @@ void main() {
|
|||
print('5. Compound Interest Formula');
|
||||
final compoundInterestFormula = Formula(
|
||||
name: 'Compound Interest',
|
||||
input: {
|
||||
'P': VariableSpec(magnitude: 'currency'), // Principal
|
||||
'r': VariableSpec(magnitude: 'rate'), // Annual interest rate
|
||||
'n': VariableSpec(magnitude: 'count'), // Times compounded per year
|
||||
't': VariableSpec(magnitude: 'time'), // Time in years
|
||||
},
|
||||
output: {
|
||||
'A': VariableSpec(magnitude: 'currency'), // Final amount
|
||||
},
|
||||
input: [
|
||||
VariableSpec(name: 'P', magnitude: 'currency'), // Principal
|
||||
VariableSpec(name: 'r', magnitude: 'rate'), // Annual interest rate
|
||||
VariableSpec(name: 'n', magnitude: 'count'), // Times compounded per year
|
||||
VariableSpec(name: 't', magnitude: 'time'), // Time in years
|
||||
],
|
||||
output: VariableSpec(name: 'A', magnitude: 'currency'), // Final amount
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
// A = P * (1 + r/n)^(n*t)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
/// Formula evaluator that executes d4rt code with input variables and
|
||||
/// returns the value of the single output variable.
|
||||
///
|
||||
/// The evaluator assumes that:
|
||||
/// - A formula has exactly one output variable
|
||||
/// - The d4rt code defines a main function with parameters matching input variables
|
||||
/// - The d4rt code when executed returns the value of that output variable
|
||||
/// - Input variables are provided as a Map<String, dynamic>
|
||||
|
||||
import 'package:d4rt/d4rt.dart';
|
||||
import 'formula_models.dart';
|
||||
|
|
@ -73,7 +65,7 @@ class FormulaEvaluator {
|
|||
void _validateInputValues(Formula formula, Map<String, dynamic> inputValues) {
|
||||
final missingVars = <String>[];
|
||||
|
||||
for (final inputVar in formula.input.keys) {
|
||||
for (final inputVar in formula.inputVarNames()) {
|
||||
if (!inputValues.containsKey(inputVar)) {
|
||||
missingVars.add(inputVar);
|
||||
}
|
||||
|
|
@ -89,19 +81,18 @@ class FormulaEvaluator {
|
|||
|
||||
/// Gets the name of the single output variable from the formula
|
||||
String getOutputVariableName(Formula formula) {
|
||||
// Formula construction already ensures exactly one output variable
|
||||
return formula.output.keys.first;
|
||||
return formula.output.name;
|
||||
}
|
||||
|
||||
/// Gets the magnitude of the single output variable from the formula
|
||||
String getOutputVariableMagnitude(Formula formula) {
|
||||
// Formula construction already ensures exactly one output variable
|
||||
return formula.output.values.first.magnitude;
|
||||
return formula.output.magnitude;
|
||||
}
|
||||
|
||||
/// Gets the ordered list of input variable names (alphabetically sorted)
|
||||
List<String> getInputVariableOrder(Formula formula) {
|
||||
return formula.input.keys.toList()..sort();
|
||||
return formula.inputVarNames()..sort();
|
||||
}
|
||||
|
||||
/// Builds the complete d4rt source code by injecting variable declarations
|
||||
|
|
|
|||
|
|
@ -1,49 +1,33 @@
|
|||
/// Data classes to represent a formula and its I/O specs.
|
||||
///
|
||||
/// Structure (from README.md):
|
||||
/// - name: String
|
||||
/// - input: { varName: { magnitude: String } }
|
||||
/// - output: { varName: { magnitude: String } }
|
||||
/// - d4rt_code: { code: String } or String
|
||||
///
|
||||
/// - Accept d4rt_code as either a plain string or an object { code: "..." }.
|
||||
|
||||
import 'package:d4rt/d4rt.dart';
|
||||
|
||||
class VariableSpec {
|
||||
|
||||
final String name;
|
||||
final String magnitude;
|
||||
static final MAGNITUDELESS = "magnitudeless";
|
||||
|
||||
const VariableSpec({required this.magnitude});
|
||||
|
||||
factory VariableSpec.fromJson(Map<String, dynamic> json) {
|
||||
final mag = json['magnitude'];
|
||||
if (mag is! String || mag.trim().isEmpty) {
|
||||
throw FormatException("'magnitude' must be a non-empty string");
|
||||
}
|
||||
return VariableSpec(magnitude: mag);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {'magnitude': magnitude};
|
||||
VariableSpec({required this.name, required this.magnitude});
|
||||
|
||||
@override
|
||||
String toString() => 'VariableSpec(magnitude: $magnitude)';
|
||||
|
||||
VariableSpec copyWith({String? magnitude}) =>
|
||||
VariableSpec(magnitude: magnitude ?? this.magnitude);
|
||||
String toString() => 'var($name: $magnitude)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is VariableSpec &&
|
||||
runtimeType == other.runtimeType &&
|
||||
magnitude == other.magnitude;
|
||||
magnitude == other.magnitude &&
|
||||
name == other.name;
|
||||
|
||||
@override
|
||||
int get hashCode => magnitude.hashCode;
|
||||
int get hashCode => Object.hash(magnitude, name);
|
||||
}
|
||||
|
||||
class Formula {
|
||||
final String name;
|
||||
final Map<String, VariableSpec> input; // Supports multiple input variables
|
||||
final Map<String, VariableSpec> output; // Supports multiple output variables
|
||||
final List<VariableSpec> input;
|
||||
final VariableSpec output;
|
||||
final String d4rtCode;
|
||||
|
||||
Formula({
|
||||
|
|
@ -59,116 +43,27 @@ class Formula {
|
|||
if (name.trim().isEmpty) {
|
||||
throw ArgumentError('Formula name cannot be empty');
|
||||
}
|
||||
if (output.length != 1) {
|
||||
throw ArgumentError(
|
||||
'Formula "$name" must have exactly one output variable, '
|
||||
'but has ${output.length}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
factory Formula.fromJson(Map<String, dynamic> json) {
|
||||
final name = json['name'];
|
||||
if (name is! String || name.trim().isEmpty) {
|
||||
throw FormatException('Formula requires a non-empty name string');
|
||||
}
|
||||
|
||||
Map<String, VariableSpec> parseVars(dynamic obj, String fieldName) {
|
||||
if (obj == null) return <String, VariableSpec>{};
|
||||
if (obj is! Map<String, dynamic>) {
|
||||
throw FormatException('$fieldName must be an object map');
|
||||
}
|
||||
return obj.map((k, v) {
|
||||
if (v is! Map<String, dynamic>) {
|
||||
throw FormatException(
|
||||
'Variable "$k" in $fieldName must be an object',
|
||||
);
|
||||
}
|
||||
return MapEntry(k, VariableSpec.fromJson(v));
|
||||
});
|
||||
}
|
||||
|
||||
String parseCode(dynamic code) {
|
||||
if (code == null) {
|
||||
throw FormatException('d4rt_code is required');
|
||||
}
|
||||
if (code is String) return code;
|
||||
if (code is Map<String, dynamic>) {
|
||||
final explicit = code['code'];
|
||||
if (explicit is String) return explicit;
|
||||
for (final entry in code.entries) {
|
||||
if (entry.value is String) return entry.value as String;
|
||||
}
|
||||
}
|
||||
throw FormatException(
|
||||
'd4rt_code must be a string or an object containing a code string',
|
||||
);
|
||||
}
|
||||
|
||||
final input = parseVars(json['input'], 'input');
|
||||
final output = parseVars(json['output'], 'output');
|
||||
final d4rtCode = parseCode(json['d4rt_code']);
|
||||
|
||||
return Formula(
|
||||
name: name,
|
||||
input: input,
|
||||
output: output,
|
||||
d4rtCode: d4rtCode,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'input': input.map((k, v) => MapEntry(k, v.toJson())),
|
||||
'output': output.map((k, v) => MapEntry(k, v.toJson())),
|
||||
'd4rt_code': {'code': d4rtCode},
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Formula(name: $name, input: $input, output: $output, d4rtCode: $d4rtCode)';
|
||||
|
||||
Formula copyWith({
|
||||
String? name,
|
||||
Map<String, VariableSpec>? input,
|
||||
Map<String, VariableSpec>? output,
|
||||
String? d4rtCode,
|
||||
}) => Formula(
|
||||
name: name ?? this.name,
|
||||
input: input ?? this.input,
|
||||
output: output ?? this.output,
|
||||
d4rtCode: d4rtCode ?? this.d4rtCode,
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Formula &&
|
||||
runtimeType == other.runtimeType &&
|
||||
name == other.name &&
|
||||
_mapEquals(input, other.input) &&
|
||||
_mapEquals(output, other.output) &&
|
||||
output == other.output &&
|
||||
ListEquality().equals(input, other.input) &&
|
||||
d4rtCode == other.d4rtCode;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(name, _mapHash(input), _mapHash(output), d4rtCode);
|
||||
Object.hash(name, ListEquality().hash(input), output, d4rtCode);
|
||||
|
||||
List<String> inputVarNames() => input.map( (v) => v.name ).toList(growable: false);
|
||||
}
|
||||
|
||||
bool _mapEquals<K, V>(Map<K, V> a, Map<K, V> b) {
|
||||
if (identical(a, b)) return true;
|
||||
if (a.length != b.length) return false;
|
||||
for (final entry in a.entries) {
|
||||
if (!b.containsKey(entry.key)) return false;
|
||||
if (b[entry.key] != entry.value) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int _mapHash<K, V>(Map<K, V> m) {
|
||||
var h = 0;
|
||||
for (final e in m.entries) {
|
||||
h = h ^ Object.hash(e.key, e.value);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ void main() {
|
|||
test('evaluates Newton\'s second law formula', () {
|
||||
final formula = Formula(
|
||||
name: "Newton's second law",
|
||||
input: {
|
||||
'm': VariableSpec(magnitude: 'mass'),
|
||||
'a': VariableSpec(magnitude: 'acceleration'),
|
||||
},
|
||||
output: {'F': VariableSpec(magnitude: 'force')},
|
||||
input: [
|
||||
VariableSpec(name: 'm', magnitude: 'mass'),
|
||||
VariableSpec(name: 'a', magnitude: 'acceleration'),
|
||||
],
|
||||
output: VariableSpec(name: 'F', magnitude: 'force'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return a * m;
|
||||
|
|
@ -37,11 +37,11 @@ void main() {
|
|||
test('evaluates simple arithmetic formula', () {
|
||||
final formula = Formula(
|
||||
name: 'Simple addition',
|
||||
input: {
|
||||
'x': VariableSpec(magnitude: 'scalar'),
|
||||
'y': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [
|
||||
VariableSpec(name: 'x', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'y', magnitude: 'scalar'),
|
||||
],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return x + y;
|
||||
|
|
@ -57,8 +57,8 @@ void main() {
|
|||
test('handles single input variable', () {
|
||||
final formula = Formula(
|
||||
name: 'Square function',
|
||||
input: {'n': VariableSpec(magnitude: 'scalar')},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [VariableSpec(name: 'n', magnitude: 'scalar')],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return n * n;
|
||||
|
|
@ -73,12 +73,12 @@ void main() {
|
|||
test('handles complex mathematical operations', () {
|
||||
final formula = Formula(
|
||||
name: 'Quadratic formula discriminant',
|
||||
input: {
|
||||
'a': VariableSpec(magnitude: 'scalar'),
|
||||
'b': VariableSpec(magnitude: 'scalar'),
|
||||
'c': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
output: {'discriminant': VariableSpec(magnitude: 'scalar')},
|
||||
input: [
|
||||
VariableSpec(name: 'a', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'b', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'c', magnitude: 'scalar'),
|
||||
],
|
||||
output: VariableSpec(name: 'discriminant', magnitude: 'scalar'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
return b * b - 4 * a * c;
|
||||
|
|
@ -96,12 +96,12 @@ void main() {
|
|||
test('maintains consistent alphabetical order for input variables', () {
|
||||
final formula = Formula(
|
||||
name: 'Test order',
|
||||
input: {
|
||||
'z': VariableSpec(magnitude: 'scalar'),
|
||||
'a': VariableSpec(magnitude: 'scalar'),
|
||||
'b': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [
|
||||
VariableSpec(name: 'z', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'a', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'b', magnitude: 'scalar'),
|
||||
],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: 'main() { return a + b + z; }',
|
||||
);
|
||||
|
||||
|
|
@ -112,12 +112,12 @@ void main() {
|
|||
test('passes arguments in correct alphabetical order', () {
|
||||
final formula = Formula(
|
||||
name: 'Test argument order',
|
||||
input: {
|
||||
'z': VariableSpec(magnitude: 'scalar'),
|
||||
'a': VariableSpec(magnitude: 'scalar'),
|
||||
'y': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [
|
||||
VariableSpec(name: 'z', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'a', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'y', magnitude: 'scalar'),
|
||||
],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: '''
|
||||
main() {
|
||||
// Variables: a=1, y=2, z=3
|
||||
|
|
@ -133,46 +133,15 @@ void main() {
|
|||
});
|
||||
|
||||
group('Error handling', () {
|
||||
test(
|
||||
'throws exception for formula with no output variables during construction',
|
||||
() {
|
||||
expect(() {
|
||||
return Formula(
|
||||
name: 'Invalid formula',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {}, // No output variables
|
||||
d4rtCode: 'main() { return x; }',
|
||||
);
|
||||
}, throwsA(isA<ArgumentError>()));
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'throws exception for formula with multiple output variables during construction',
|
||||
() {
|
||||
expect(
|
||||
() => Formula(
|
||||
name: 'Invalid formula',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {
|
||||
'y': VariableSpec(magnitude: 'scalar'),
|
||||
'z': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
d4rtCode: 'main() { return x; }',
|
||||
),
|
||||
throwsA(isA<ArgumentError>()),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test('throws exception for missing input variables', () {
|
||||
final formula = Formula(
|
||||
name: 'Test formula',
|
||||
input: {
|
||||
'x': VariableSpec(magnitude: 'scalar'),
|
||||
'y': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [
|
||||
VariableSpec(name: 'x', magnitude: 'scalar'),
|
||||
VariableSpec(name: 'y', magnitude: 'scalar'),
|
||||
],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: 'main() { return x + y; }',
|
||||
);
|
||||
|
||||
|
|
@ -185,8 +154,8 @@ void main() {
|
|||
test('throws exception for invalid d4rt code', () {
|
||||
final formula = Formula(
|
||||
name: 'Invalid code formula',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {'result': VariableSpec(magnitude: 'scalar')},
|
||||
input: [VariableSpec(name: 'x', magnitude: 'scalar')],
|
||||
output: VariableSpec(name: 'result', magnitude: 'scalar'),
|
||||
d4rtCode: 'invalid dart code here!',
|
||||
);
|
||||
|
||||
|
|
@ -201,8 +170,8 @@ void main() {
|
|||
test('getOutputVariableName returns the single output variable name', () {
|
||||
final formula = Formula(
|
||||
name: 'Test',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {'force': VariableSpec(magnitude: 'Newton')},
|
||||
input: [VariableSpec(name: 'x', magnitude: 'scalar')],
|
||||
output: VariableSpec(name: 'force', magnitude: 'Newton'),
|
||||
d4rtCode: 'main() { return x; }',
|
||||
);
|
||||
|
||||
|
|
@ -214,8 +183,8 @@ void main() {
|
|||
() {
|
||||
final formula = Formula(
|
||||
name: 'Test',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {'force': VariableSpec(magnitude: 'Newton')},
|
||||
input: [VariableSpec(name: 'x', magnitude: 'scalar')],
|
||||
output: VariableSpec(name: 'force', magnitude: 'Newton'),
|
||||
d4rtCode: 'main() { return x; }',
|
||||
);
|
||||
|
||||
|
|
@ -226,8 +195,8 @@ void main() {
|
|||
test('utility methods work correctly with valid formulas', () {
|
||||
final validFormula = Formula(
|
||||
name: 'Valid Formula',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {'result': VariableSpec(magnitude: 'Newton')},
|
||||
input: [VariableSpec(name: 'x', magnitude: 'scalar')],
|
||||
output: VariableSpec(name: 'result', magnitude: 'Newton'),
|
||||
d4rtCode: 'main() { return x; }',
|
||||
);
|
||||
|
||||
|
|
@ -235,39 +204,14 @@ void main() {
|
|||
expect(evaluator.getOutputVariableMagnitude(validFormula), 'Newton');
|
||||
});
|
||||
|
||||
test('validates formula construction with factory method', () {
|
||||
// Test the factory method validation
|
||||
expect(
|
||||
() => Formula(
|
||||
name: 'Invalid',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {}, // No output variables
|
||||
d4rtCode: 'main() { return x; }',
|
||||
),
|
||||
throwsA(isA<ArgumentError>()),
|
||||
);
|
||||
|
||||
expect(
|
||||
() => Formula(
|
||||
name: 'Invalid',
|
||||
input: {'x': VariableSpec(magnitude: 'scalar')},
|
||||
output: {
|
||||
'y': VariableSpec(magnitude: 'scalar'),
|
||||
'z': VariableSpec(magnitude: 'scalar'),
|
||||
},
|
||||
d4rtCode: 'main() { return x; }',
|
||||
),
|
||||
throwsA(isA<ArgumentError>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Data types', () {
|
||||
test('handles integer values', () {
|
||||
final formula = Formula(
|
||||
name: 'Integer test',
|
||||
input: {'n': VariableSpec(magnitude: 'count')},
|
||||
output: {'result': VariableSpec(magnitude: 'count')},
|
||||
input: [VariableSpec(name: 'n', magnitude: 'count')],
|
||||
output: VariableSpec(name: 'result', magnitude: 'count'),
|
||||
d4rtCode: 'main() { return n + 1; }',
|
||||
);
|
||||
|
||||
|
|
@ -278,8 +222,8 @@ void main() {
|
|||
test('handles double values', () {
|
||||
final formula = Formula(
|
||||
name: 'Double test',
|
||||
input: {'x': VariableSpec(magnitude: 'length')},
|
||||
output: {'result': VariableSpec(magnitude: 'area')},
|
||||
input: [VariableSpec(name: 'x', magnitude: 'length')],
|
||||
output: VariableSpec(name: 'result', magnitude: 'area'),
|
||||
d4rtCode: 'main() { return x * x; }',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,71 +4,4 @@ import 'package:test/test.dart';
|
|||
import 'package:d4rt_formulas/formula_models.dart';
|
||||
|
||||
void main() {
|
||||
group('Formula models', () {
|
||||
test('parses a formula with multiple input variables', () {
|
||||
const jsonStr = '''
|
||||
{
|
||||
"name": "Newton's second law (scalar)",
|
||||
"input": {
|
||||
"m": {"magnitude": "mass"},
|
||||
"a": {"magnitude": "acceleration"}
|
||||
},
|
||||
"output": {
|
||||
"F": {"magnitude": "Force"}
|
||||
},
|
||||
"d4rt_code": {"code": "return m*a;"}
|
||||
}
|
||||
''';
|
||||
|
||||
final map = jsonDecode(jsonStr) as Map<String, dynamic>;
|
||||
final f = Formula.fromJson(map);
|
||||
|
||||
expect(f.name, "Newton's second law (scalar)");
|
||||
expect(f.input.length, 2);
|
||||
expect(f.input['m']!.magnitude, 'mass');
|
||||
expect(f.input['a']!.magnitude, 'acceleration');
|
||||
expect(f.output.length, 1);
|
||||
expect(f.output['F']!.magnitude, 'Force');
|
||||
expect(f.d4rtCode, 'return m*a;');
|
||||
|
||||
final back = f.toJson();
|
||||
expect(back['name'], f.name);
|
||||
expect((back['input'] as Map)['m']['magnitude'], 'mass');
|
||||
expect((back['input'] as Map)['a']['magnitude'], 'acceleration');
|
||||
expect((back['output'] as Map)['F']['magnitude'], 'Force');
|
||||
expect((back['d4rt_code'] as Map)['code'], 'return m*a;');
|
||||
});
|
||||
|
||||
test('rejects typo magitude (must be magnitude)', () {
|
||||
const badJson = '''
|
||||
{
|
||||
"name": "Bad formula",
|
||||
"input": {
|
||||
"x": {"magitude": "oops"}
|
||||
},
|
||||
"output": {
|
||||
"y": {"magnitude": "ok"}
|
||||
},
|
||||
"d4rt_code": "return x;"
|
||||
}
|
||||
''';
|
||||
|
||||
final map = jsonDecode(badJson) as Map<String, dynamic>;
|
||||
expect(() => Formula.fromJson(map), throwsFormatException);
|
||||
});
|
||||
|
||||
test('accepts d4rt_code as a plain string', () {
|
||||
const jsonStr = '''
|
||||
{
|
||||
"name": "Simple",
|
||||
"input": {"x": {"magnitude": "scalar"}},
|
||||
"output": {"y": {"magnitude": "scalar"}},
|
||||
"d4rt_code": "return x;"
|
||||
}
|
||||
''';
|
||||
final map = jsonDecode(jsonStr) as Map<String, dynamic>;
|
||||
final f = Formula.fromJson(map);
|
||||
expect(f.d4rtCode, 'return x;');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue