Add initial unit tests; enhance Chart and Milestone widgets
parent
473db9335e
commit
880696ad18
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_application_1/calculator.dart';
|
import 'package:flutter_application_1/calculator.dart';
|
||||||
import 'package:flutter_application_1/enums.dart';
|
import 'package:flutter_application_1/enums.dart';
|
||||||
import 'package:flutter_application_1/translations.dart';
|
|
||||||
import 'package:flutter_application_1/utils.dart';
|
import 'package:flutter_application_1/utils.dart';
|
||||||
import 'package:flutter_application_1/widgets/input_widget.dart';
|
import 'package:flutter_application_1/widgets/input_widget.dart';
|
||||||
import 'package:flutter_application_1/widgets/interval_widget.dart';
|
import 'package:flutter_application_1/widgets/interval_widget.dart';
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import 'package:flutter_application_1/enums.dart';
|
|
||||||
|
|
||||||
String translateInterval(PayoutInterval interval) {
|
|
||||||
switch (interval) {
|
|
||||||
case PayoutInterval.yearly:
|
|
||||||
return 'jährlich';
|
|
||||||
case PayoutInterval.monthly:
|
|
||||||
return 'monatlich';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_application_1/enums.dart';
|
||||||
|
|
||||||
// Rundet den Wert im Textfeld-Controller auf die nächste ganze Zahl
|
// Rundet den Wert im Textfeld-Controller auf die nächste ganze Zahl
|
||||||
void roundToInteger(TextEditingController controller) {
|
void roundToInteger(TextEditingController controller) {
|
||||||
|
@ -19,4 +20,13 @@ void restoreDefaultValuesIfEmpty(TextEditingController controller) {
|
||||||
if (controller.text.isEmpty) {
|
if (controller.text.isEmpty) {
|
||||||
controller.text = '0';
|
controller.text = '0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String translateInterval(PayoutInterval interval) {
|
||||||
|
switch (interval) {
|
||||||
|
case PayoutInterval.yearly:
|
||||||
|
return 'jährlich';
|
||||||
|
case PayoutInterval.monthly:
|
||||||
|
return 'monatlich';
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
|
||||||
// Widget zur Erstellung eines gestapelten Säulendiagramms
|
// Widget zur Erstellung eines gestapelten Säulendiagramms
|
||||||
|
@ -79,3 +80,155 @@ class SalesData {
|
||||||
|
|
||||||
SalesData(this.year, this.value);
|
SalesData(this.year, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget, welches das Diagramm auf eine neue Seite auslagert
|
||||||
|
@override
|
||||||
|
Widget buildChartPage(BuildContext context, List<double> investedMoneyList, List<double> compoundInterestList) {
|
||||||
|
return Scaffold(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(left: 10, right: 10, top: MediaQuery.of(context).padding.top + 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(CupertinoIcons.chevron_left, size: 15), // Zurück-Pfeil
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Grafik',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 40), // Platzhalter für zentrierte Ausrichtung
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter( // Diagramm Anzeigen
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: StackedColumnChart(
|
||||||
|
lowerValues: investedMoneyList,
|
||||||
|
upperValues: compoundInterestList,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter( // Tabelle mit allen Werten anzeigen
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CupertinoColors.black,
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Table(
|
||||||
|
columnWidths: const {
|
||||||
|
0: FixedColumnWidth(60), // Spaltenbreite für die erste Spalte verringern
|
||||||
|
1: FlexColumnWidth(),
|
||||||
|
2: FlexColumnWidth(),
|
||||||
|
3: FlexColumnWidth(),
|
||||||
|
},
|
||||||
|
border: TableBorder.symmetric(
|
||||||
|
inside: const BorderSide(color: CupertinoColors.white, width: 1),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
const TableRow(
|
||||||
|
decoration: BoxDecoration(color: CupertinoColors.darkBackgroundGray),
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Jahr',
|
||||||
|
style: TextStyle(
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Einzahlungen',
|
||||||
|
style: TextStyle(
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Zinsen',
|
||||||
|
style: TextStyle(
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Endkapital',
|
||||||
|
style: TextStyle(
|
||||||
|
color: CupertinoColors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
for (int i = 0; i < investedMoneyList.length; i++)
|
||||||
|
TableRow(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'${i + 1}',
|
||||||
|
style: const TextStyle(color: CupertinoColors.white),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'€${investedMoneyList[i]}',
|
||||||
|
style: const TextStyle(color: CupertinoColors.white),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'€${compoundInterestList[i]}',
|
||||||
|
style: const TextStyle(color: CupertinoColors.white),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'€${compoundInterestList[i] + investedMoneyList[i]}',
|
||||||
|
style: const TextStyle(color: CupertinoColors.white),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_application_1/enums.dart';
|
import 'package:flutter_application_1/enums.dart';
|
||||||
import 'package:flutter_application_1/translations.dart';
|
import 'package:flutter_application_1/utils.dart';
|
||||||
|
|
||||||
class IntervalWidget extends StatefulWidget {
|
class IntervalWidget extends StatefulWidget {
|
||||||
final String selectedInterval;
|
final String selectedInterval;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Erstellt eine Zeitleiste für Meilensteine
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// Erstellt eine Zeitleiste für Meilensteine
|
||||||
Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double totalInterest) {
|
Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double totalInterest) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
child: Center(
|
child: Center(
|
||||||
|
@ -50,3 +51,41 @@ Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double tota
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget, welches den Meilenstein-Zeitstrahl auf eine neue Seite auslagert
|
||||||
|
@override
|
||||||
|
Widget buildMilestonePage(BuildContext context, String compoundInterest, String investedMoney, List<Map<String, dynamic>> milestoneList) {
|
||||||
|
return Scaffold(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(left: 10, right: 10, top: MediaQuery.of(context).padding.top + 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(CupertinoIcons.chevron_left, size: 15), // Zurück-Pfeil
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Grafik',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 40), // Platzhalter für zentrierte Ausrichtung
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter( // Meilenstein-Zeitstrahl anzeigen
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: buildMilestoneTimeline(milestoneList, double.parse(compoundInterest) - double.parse(investedMoney))
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_application_1/enums.dart';
|
import 'package:flutter_application_1/enums.dart';
|
||||||
import 'package:flutter_application_1/translations.dart';
|
import 'package:flutter_application_1/utils.dart';
|
||||||
import 'package:flutter_application_1/widgets/second_page_widget.dart';
|
|
||||||
import 'package:flutter_application_1/widgets/custom_image_button_widget.dart';
|
import 'package:flutter_application_1/widgets/custom_image_button_widget.dart';
|
||||||
import 'package:flutter_application_1/widgets/chart_widget.dart';
|
import 'package:flutter_application_1/widgets/chart_widget.dart';
|
||||||
import 'package:flutter_application_1/widgets/milestone_timeline_widget.dart';
|
import 'package:flutter_application_1/widgets/milestone_timeline_widget.dart';
|
||||||
|
@ -20,18 +19,20 @@ Widget buildResultWidget(BuildContext context, String compoundInterest, String i
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
_buildResultRow('Endkapital:', '$compoundInterest€'),
|
||||||
|
_buildResultRow('Einzahlungen:', '$investedMoney€'),
|
||||||
|
_buildResultRow('Erhaltene Zinsen:', '${double.parse(compoundInterest) + double.parse(investedMoney)}€'),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
'Wenn du über einen Zeitraum von $time Jahren ${translateInterval(payoutInterval)} $monthlySavingsRate€ mit einem Zinssatz von $interestRate% investierst, erreichst du am Ende ein Endkapital von $compoundInterest€. Dieses setzt sich aus Einzahlungen von $investedMoney€ und Zinsen bzw. Kapitalerträgen in Höhe von ${double.parse(compoundInterest) - double.parse(investedMoney)}€ zusammen.'
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
CustomImageButton(
|
CustomImageButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => SecondPage(
|
builder: (context) => buildChartPage(context, investedMoneyList, compoundInterestList),
|
||||||
title: 'Grafik',
|
|
||||||
widgetToShow: StackedColumnChart(
|
|
||||||
lowerValues: investedMoneyList,
|
|
||||||
upperValues: compoundInterestList,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -47,10 +48,7 @@ Widget buildResultWidget(BuildContext context, String compoundInterest, String i
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => SecondPage(
|
builder: (context) => buildMilestonePage(context, compoundInterest, investedMoney, milestoneList),
|
||||||
title: 'Meilensteine',
|
|
||||||
widgetToShow: buildMilestoneTimeline(milestoneList, double.parse(compoundInterest) - double.parse(investedMoney))
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -60,14 +58,6 @@ Widget buildResultWidget(BuildContext context, String compoundInterest, String i
|
||||||
style: TextStyle(color: CupertinoColors.white, fontSize: 20),
|
style: TextStyle(color: CupertinoColors.white, fontSize: 20),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildResultRow('Endkapital:', '$compoundInterest€'),
|
|
||||||
_buildResultRow('Einzahlungen:', '$investedMoney€'),
|
|
||||||
_buildResultRow('Erhaltene Zinsen:', '${double.parse(compoundInterest) - double.parse(investedMoney)}€'),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Text(
|
|
||||||
'Wenn du über einen Zeitraum von $time Jahren ${translateInterval(payoutInterval)} $monthlySavingsRate€ mit einem Zinssatz von $interestRate% investierst, erreichst du am Ende ein Endkapital von $compoundInterest€. Dieses setzt sich aus Einzahlungen von $investedMoney€ und Zinsen bzw. Kapitalerträgen in Höhe von ${double.parse(compoundInterest) - double.parse(investedMoney)}€ zusammen.'
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SecondPage extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final Widget widgetToShow;
|
|
||||||
|
|
||||||
const SecondPage({
|
|
||||||
super.key,
|
|
||||||
required this.title,
|
|
||||||
required this.widgetToShow
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: CustomScrollView(
|
|
||||||
slivers: <Widget>[
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: MediaQuery.of(context).padding.top + 10),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(CupertinoIcons.chevron_left, size: 15), // Zurück-Pfeil
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 40), // Platzhalter für zentrierte Ausrichtung
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(10.0),
|
|
||||||
child: widgetToShow, // Anzeigen des mitgegebenen Widgets
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:flutter_application_1/enums.dart';
|
||||||
|
import 'package:flutter_application_1/calculator.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('Calculation Tests', () {
|
||||||
|
test('Test calculateInvestedMoney function', () {
|
||||||
|
// Testen mit verschiedenen Eingabewerten
|
||||||
|
expect(calculateInvestedMoney(1000, 100, 5, []), equals(7000.0));
|
||||||
|
expect(calculateInvestedMoney(2000, 50, 10, []), equals(8000.0));
|
||||||
|
});
|
||||||
|
test('Test calculateCompoundInterest function', () {
|
||||||
|
// Testen mit jährlicher Auszahlung
|
||||||
|
List<double> investedMoneyListYearly = [];
|
||||||
|
List<double> compoundInterestListYearly = [];
|
||||||
|
calculateInvestedMoney(1000, 100, 10, investedMoneyListYearly);
|
||||||
|
expect(calculateCompoundInterest(1000, 100, 5, 10, PayoutInterval.yearly, investedMoneyListYearly, compoundInterestListYearly), equals(16722.0));
|
||||||
|
|
||||||
|
// Testen mit monatlicher Auszahlung
|
||||||
|
List<double> investedMoneyListMonthly = [];
|
||||||
|
List<double> compoundInterestListMonthly = [];
|
||||||
|
calculateInvestedMoney(2000, 50, 10, investedMoneyListMonthly);
|
||||||
|
expect(calculateCompoundInterest(2000, 50, 5, 10, PayoutInterval.monthly, investedMoneyListMonthly, compoundInterestListMonthly), equals(11058.0));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group('Edge Case Tests', () {
|
||||||
|
test('Test calculateInvestedMoney function with extremely high input values', () {
|
||||||
|
// Testen mit extrem hohen Eingabewerten
|
||||||
|
expect(calculateInvestedMoney(1e15, 1e12, 100, []), equals(2.2e15));
|
||||||
|
});
|
||||||
|
test('Test calculateInvestedMoney function with extremely low input values', () {
|
||||||
|
// Testen mit extrem niedrigen Eingabewerten
|
||||||
|
expect(calculateInvestedMoney(0, 0, 0, []), equals(0.0));
|
||||||
|
expect(calculateInvestedMoney(0.1, 0.01, 0.001, []), equals(0.0));
|
||||||
|
});
|
||||||
|
test('Test calculateCompoundInterest function with extremely high interest rate', () {
|
||||||
|
// Testen mit extrem hohen Zinssatz
|
||||||
|
List<double> investedMoneyListHighInterest = [];
|
||||||
|
List<double> compoundInterestListHighInterest = [];
|
||||||
|
calculateInvestedMoney(1000, 100, 10, investedMoneyListHighInterest);
|
||||||
|
expect(calculateCompoundInterest(1000, 100, 1000, 10, PayoutInterval.yearly, investedMoneyListHighInterest, compoundInterestListHighInterest), equals(29049915553000.0));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
Loading…
Reference in New Issue