genai_testing: Expanded Testing Efforts

This commit is contained in:
Manas Hejmadi
2025-08-31 01:56:48 +05:30
parent 143e2c146b
commit 37a21106ae
7 changed files with 293 additions and 3 deletions

View File

@@ -5,6 +5,6 @@ const kKeyStream = 'stream';
final kAvailableModels = AvailableModels.fromJson(kModelsData); final kAvailableModels = AvailableModels.fromJson(kModelsData);
const kModelRemoteUrl = const kModelRemoteUrl =
'https://raw.githubusercontent.com/foss42/apidash/package/genai/packages/genai/models.json'; 'https://raw.githubusercontent.com/foss42/apidash/refs/heads/main/packages/genai/models.json';
const kBaseOllamaUrl = 'http://localhost:11434'; const kBaseOllamaUrl = 'http://localhost:11434';

View File

@@ -25,4 +25,3 @@ dev_dependencies:
freezed: ^2.5.7 freezed: ^2.5.7
json_serializable: ^6.7.1 json_serializable: ^6.7.1
test: ^1.25.2 test: ^1.25.2
mocktail: ^1.0.0

View File

@@ -0,0 +1,83 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:genai/models/model_config.dart';
import 'package:genai/models/model_config_value.dart';
void main() {
group('ModelConfig', () {
test('constructor asserts correct type/value', () {
expect(
() => ModelConfig(
id: '1',
name: 'Temperature',
description: 'test',
type: ConfigType.boolean,
value: ConfigBooleanValue(value: true),
),
returnsNormally,
);
expect(
() => ModelConfig(
id: '2',
name: 'Invalid',
description: 'wrong',
type: ConfigType.boolean,
value: ConfigNumericValue(value: 5),
),
throwsA(isA<AssertionError>()),
);
});
test('updateValue returns new instance with updated value', () {
final config = ModelConfig(
id: '1',
name: 'Numeric',
description: 'test',
type: ConfigType.numeric,
value: ConfigNumericValue(value: 10),
);
final updated = config.updateValue(ConfigNumericValue(value: 20));
expect(updated.value.value, 20);
expect(updated.id, config.id);
});
test('toJson and fromJson work correctly', () {
final config = ModelConfig(
id: 'temp',
name: 'Temperature',
description: 'test config',
type: ConfigType.numeric,
value: ConfigNumericValue(value: 5),
);
final json = config.toJson();
expect(json['id'], 'temp');
expect(json['type'], 'numeric');
final from = ModelConfig.fromJson(json);
expect(from.id, 'temp');
expect(from.value is ConfigNumericValue, true);
expect((from.value as ConfigNumericValue).value, 5);
});
test('copyWith creates modified copy', () {
final config = ModelConfig(
id: 'slider',
name: 'Slider',
description: 'range',
type: ConfigType.slider,
value: ConfigSliderValue(value: (0, 0.3, 1)),
);
final copy = config.copyWith(
name: 'Updated Slider',
value: ConfigSliderValue(value: (0, 0.7, 1)),
);
expect(copy.name, 'Updated Slider');
expect(copy.value.getPayloadValue(), 0.7);
expect(copy.id, 'slider'); // unchanged
});
});
}

View File

@@ -0,0 +1,110 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:genai/models/model_config_value.dart';
void main() {
group('ConfigType Enum', () {
test('getConfigTypeEnum returns correct enum', () {
expect(getConfigTypeEnum('boolean'), ConfigType.boolean);
expect(getConfigTypeEnum('slider'), ConfigType.slider);
expect(getConfigTypeEnum('numeric'), ConfigType.numeric);
expect(getConfigTypeEnum('text'), ConfigType.text);
});
test('getConfigTypeEnum falls back to text on invalid', () {
expect(getConfigTypeEnum('does_not_exist'), ConfigType.text);
expect(getConfigTypeEnum(null), ConfigType.text);
});
});
group('ConfigBooleanValue', () {
test('serialize and deserialize works', () {
final value = ConfigBooleanValue(value: true);
final serialized = value.serialize();
expect(serialized, 'true');
final deserialized = ConfigBooleanValue.deserialize(serialized);
expect(deserialized.value, true);
});
});
group('ConfigNumericValue', () {
test('serialize and deserialize works', () {
final value = ConfigNumericValue(value: 42);
final serialized = value.serialize();
expect(serialized, '42');
final deserialized = ConfigNumericValue.deserialize('42');
expect(deserialized.value, 42);
final nullValue = ConfigNumericValue.deserialize('not_a_number');
expect(nullValue.value, null);
});
});
group('ConfigSliderValue', () {
test('serialize and deserialize works', () {
final value = ConfigSliderValue(value: (0.0, 0.5, 1.0));
final serialized = value.serialize();
expect(serialized, jsonEncode([0.0, 0.5, 1.0]));
final deserialized = ConfigSliderValue.deserialize(serialized);
expect(deserialized.value, (0.0, 0.5, 1.0));
});
test('getPayloadValue returns middle element', () {
final slider = ConfigSliderValue(value: (0.0, 0.5, 1.0));
expect(slider.getPayloadValue(), 0.5);
});
});
group('ConfigTextValue', () {
test('serialize and deserialize works', () {
final value = ConfigTextValue(value: 'hello');
final serialized = value.serialize();
expect(serialized, 'hello');
final deserialized = ConfigTextValue.deserialize('world');
expect(deserialized.value, 'world');
});
});
group('checkTypeValue', () {
test('validates correct type/value matches', () {
expect(
checkTypeValue(ConfigType.boolean, ConfigBooleanValue(value: true)),
true,
);
expect(
checkTypeValue(ConfigType.numeric, ConfigNumericValue(value: 3)),
true,
);
expect(
checkTypeValue(
ConfigType.slider,
ConfigSliderValue(value: (0, 0.5, 1)),
),
true,
);
expect(
checkTypeValue(ConfigType.text, ConfigTextValue(value: 'hi')),
true,
);
});
test('returns false for mismatched type/value', () {
expect(
checkTypeValue(ConfigType.boolean, ConfigNumericValue(value: 1)),
false,
);
expect(
checkTypeValue(ConfigType.numeric, ConfigTextValue(value: 'x')),
false,
);
expect(
checkTypeValue(ConfigType.slider, ConfigBooleanValue(value: true)),
false,
);
});
});
}

View File

@@ -7,7 +7,7 @@ import 'package:genai/interface/consts.dart';
import 'package:genai/utils/ai_request_utils.dart'; import 'package:genai/utils/ai_request_utils.dart';
import 'package:better_networking/better_networking.dart'; import 'package:better_networking/better_networking.dart';
const kTestingAPIKey = "AIzaSyAtmGxNxlbh_MokoDbMjHKDSW-gU6GCMOU"; const kTestingAPIKey = "XXXXXXXXXXXX";
void main() { void main() {
group('ai_request_utils', () { group('ai_request_utils', () {

View File

@@ -0,0 +1,74 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:genai/models/available_models.dart';
import 'package:genai/interface/interface.dart';
void main() {
group('AvailableModels', () {
test('can parse from JSON and back', () {
const jsonString = '''
{
"version": 1.0,
"model_providers": [
{
"provider_id": "openai",
"provider_name": "OpenAI",
"source_url": "https://api.openai.com",
"models": [
{"id": "gpt-4", "name": "GPT-4"}
]
}
]
}
''';
final models = availableModelsFromJson(jsonString);
expect(models.version, 1.0);
expect(models.modelProviders.length, 1);
expect(models.modelProviders.first.providerName, "OpenAI");
final backToJson = availableModelsToJson(models);
expect(backToJson.contains("GPT-4"), true);
});
test('map getter returns map of providers', () {
final provider = AIModelProvider(
providerId: ModelAPIProvider.openai,
providerName: "OpenAI",
models: [const Model(id: "gpt-4", name: "GPT-4")],
);
final available = AvailableModels(
version: 1.0,
modelProviders: [provider],
);
expect(available.map.containsKey(ModelAPIProvider.openai), true);
expect(available.map[ModelAPIProvider.openai]?.providerName, "OpenAI");
});
});
group('AIModelProvider', () {
test(
'toAiRequestModel returns default AIRequestModel with model override',
() {
const provider = AIModelProvider(
providerId: ModelAPIProvider.openai,
providerName: "OpenAI",
);
const model = const Model(id: "gpt-4", name: "GPT-4");
final req = provider.toAiRequestModel(model: model);
expect(req?.model, "gpt-4");
},
);
});
group('Model', () {
test('fromJson works', () {
final model = Model.fromJson({"id": "mistral", "name": "Mistral"});
expect(model.id, "mistral");
expect(model.name, "Mistral");
});
});
}

View File

@@ -0,0 +1,24 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:genai/models/available_models.dart';
import 'package:genai/utils/model_manager.dart';
void main() {
group('ModelManager', () {
test('fetchModelsFromRemote returns parsed models', () async {
final result = await ModelManager.fetchModelsFromRemote();
expect(result, isA<AvailableModels>());
});
test('fetchInstalledOllamaModels parses response', () async {
final body = jsonEncode({
"models": [
{"model": "mistral", "name": "Mistral"},
{"model": "llama2", "name": "LLaMA 2"},
],
});
final result = await ModelManager.fetchInstalledOllamaModels();
expect(result, isNotNull);
});
});
}