diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000000000000000000000000000000000000..b12a719d583f50fcd7bfc0b2403a27a38568bccb --- /dev/null +++ b/TESTING.md @@ -0,0 +1,19 @@ +# Test Design for `example1.Example1App._find_smallest_positive` + +## Categories + +* …: …, …, …, … +* …: …, …, …, … +* …: …, …, …, … +* …: …, …, …, … + +## Initial Test Frames (by CPT) + +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) +* `entries=[…]` (…, …, …, …) diff --git a/example1.kv b/example1.kv index 8e850df7aa18ac0deca366f1525b0ca83b294210..054666d9cc3ba88699142231a5e2ea5e774ce996 100644 --- a/example1.kv +++ b/example1.kv @@ -1,8 +1,7 @@ BoxLayout: orientation: 'vertical' - BoxLayout: - id: fields - orientation: 'vertical' + Fields: + entries: app.entries size_hint: (1.0, 6.0) BoxLayout: orientation: 'horizontal' @@ -15,18 +14,19 @@ BoxLayout: font_size: sp(24) on_press: app.remove_field() Label: - id: result - text: 'Smallest Positive: inf' + text: app.result font_size: sp(24) +<Fields>: + orientation: 'vertical' + <Field>: orientation: 'horizontal' Label: - text: root.label_text + text: f'Field #{root.index}: ' font_size: sp(24) TextInput: - id: input multiline: False write_tab: False font_size: sp(24) - on_text: app.update() + on_text: app.set_entry(root.index, self.text) diff --git a/example1.py b/example1.py index f7ee4b18e9afdd031b3c4468d3c9cdeeac82dfdf..301c0af1fab3577c3771635ddd2e696e4eacd5cd 100644 --- a/example1.py +++ b/example1.py @@ -2,34 +2,58 @@ from math import inf from kivy.app import App from kivy.uix.boxlayout import BoxLayout -from kivy.properties import StringProperty +from kivy.properties import NumericProperty, StringProperty, ListProperty class Field(BoxLayout): - label_text = StringProperty() + index = NumericProperty() + entry = StringProperty() + + +class Fields(BoxLayout): + entries = ListProperty([]) # elements are strings (some may not be valid numbers) + + def rebuild(self): + while len(self.children) > len(self.entries): + self.remove_widget(self.children[0]) + while len(self.children) < len(self.entries): + self.add_widget(Field(index=len(self.children))) + + def on_entries(self, _, __): + self.rebuild() + for field, entry in zip(reversed(self.children), self.entries): + field.entry = entry class Example1App(App): + entries = ListProperty([]) # elements are strings (some may not be valid numbers) + result = StringProperty('Smallest Positive: inf') + def add_field(self): - container = self.root.ids.fields - container.add_widget(Field(label_text=f'Field #{len(container.children)}: ')) + self.entries.append('') def remove_field(self): - container = self.root.ids.fields - if len(container.children) > 0: - container.remove_widget(container.children[0]) + try: + self.entries.pop() + except IndexError: + pass def update(self): - container = self.root.ids.fields smallest_positive = inf - for field in container.children: + for entry in self.entries: try: - value = float(field.ids.input.text) + value = float(entry) if 0 < value < smallest_positive: smallest_positive = value except ValueError: pass - self.root.ids.result.text = f'Smallest Positive: {smallest_positive}' + self.result = f'Smallest Positive: {smallest_positive}' + + def on_entries(self, _, __): + self.update() + + def set_entry(self, index, entry): + self.entries[index] = entry if __name__ == '__main__': diff --git a/example2.kv b/example2.kv index 2ea9ff20a05bb1d215e651cb30212201d9476132..40deb5ff24689c8479ced6604ef5095ce3c41a93 100644 --- a/example2.kv +++ b/example2.kv @@ -1,32 +1,5 @@ BoxLayout: orientation: 'vertical' - BoxLayout: - id: fields - orientation: 'vertical' - size_hint: (1.0, 6.0) - BoxLayout: - orientation: 'horizontal' - Button: - text: 'Add Field' - font_size: sp(24) - on_press: app.add_field() - Button: - text: 'Remove Field' - font_size: sp(24) - on_press: app.remove_field() Label: - id: result text: f'Smallest Positive: {app.smallest_positive}' font_size: sp(24) - -<Field>: - orientation: 'horizontal' - Label: - text: root.label_text - font_size: sp(24) - TextInput: - id: input - multiline: False - write_tab: False - font_size: sp(24) - on_text: app.update() diff --git a/example2.py b/example2.py index 4fbaa094a1aec59d0d47e863aa4cd76a8e8a1473..3bc0c8105eb553a28e58170abf41355f38ed24aa 100644 --- a/example2.py +++ b/example2.py @@ -1,48 +1,41 @@ +from sys import stderr from math import inf -from kivy.app import App -from kivy.uix.boxlayout import BoxLayout -from kivy.properties import NumericProperty, StringProperty - +from sqlalchemy.exc import SQLAlchemyError +from values import ValueDatabase, Value -class Field(BoxLayout): - label_text = StringProperty() +from kivy.app import App +from kivy.properties import NumericProperty class Example2App(App): smallest_positive = NumericProperty(inf) - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.values = [] - - def add_field(self): - container = self.root.ids.fields - container.add_widget(Field(label_text=f'Field #{len(container.children)}: ')) - - def remove_field(self): - container = self.root.ids.fields - if len(container.children) > 0: - container.remove_widget(container.children[0]) - - def _find_smallest_positive(self): + @staticmethod + def _find_smallest_positive(values): result = inf - for value in self.values: + for value in values: if 0 < value < result: result = value return result - def update(self): - container = self.root.ids.fields - self.values = [] - for field in container.children: - try: - self.values.append(float(field.ids.input.text)) - except ValueError: - pass - self.smallest_positive = self._find_smallest_positive() + def on_start(self): + url = ValueDatabase.construct_mysql_url('localhost', 3306, 'values', 'root', 'cse1208') + value_database = ValueDatabase(url) + session = value_database.create_session() + values = [record.value for record in session.query(Value).all()] + self.smallest_positive = Example2App._find_smallest_positive(values) + + +def main(): + try: + app = Example2App() + app.run() + except SQLAlchemyError as exception: + print('Database connection failed!', file=stderr) + print(f'Cause: {exception}', file=stderr) + exit(1) if __name__ == '__main__': - app = Example2App() - app.run() + main() diff --git a/example3.kv b/example3.kv deleted file mode 100644 index b3151248706e3d6f24fc636b41e7d0cc917c5432..0000000000000000000000000000000000000000 --- a/example3.kv +++ /dev/null @@ -1,6 +0,0 @@ -BoxLayout: - orientation: 'vertical' - Label: - id: result - text: f'Smallest Positive: {app.smallest_positive}' - font_size: sp(24) diff --git a/example3.py b/example3.py deleted file mode 100644 index f6e6627880b74427e9d993375285ab6abe73741c..0000000000000000000000000000000000000000 --- a/example3.py +++ /dev/null @@ -1,41 +0,0 @@ -from sys import stderr -from math import inf - -from sqlalchemy.exc import SQLAlchemyError -from values import ValueDatabase, Value - -from kivy.app import App -from kivy.properties import NumericProperty - - -class Example3App(App): - smallest_positive = NumericProperty(inf) - - @staticmethod - def _find_smallest_positive(values): - result = inf - for value in values: - if 0 < value < result: - result = value - return result - - def on_start(self): - url = ValueDatabase.construct_mysql_url('localhost', 3306, 'values', 'root', 'cse1208') - value_database = ValueDatabase(url) - session = value_database.create_session() - values = [record.value for record in session.query(Value).all()] - self.smallest_positive = Example3App._find_smallest_positive(values) - - -def main(): - try: - app = Example3App() - app.run() - except SQLAlchemyError as exception: - print('Database connection failed!', file=stderr) - print(f'Cause: {exception}', file=stderr) - exit(1) - - -if __name__ == '__main__': - main() diff --git a/test_example2.py b/test_example2.py index d401b3565697a8b3be91fd0b93bd38cbf2ec8f70..d7c6011bc7126bff30539cde6146a371b57d7084 100644 --- a/test_example2.py +++ b/test_example2.py @@ -1,11 +1,10 @@ from unittest import TestCase +from values import ValueDatabase, Value + from example2 import Example2App class TestExample2App(TestCase): - def test_find_smallest_positive(self): - app = Example2App() - app.values = [5.0, 2.0, 4.0] - actual = app._find_smallest_positive() - self.assertEqual(actual, 2.0) + def test_database_access(self): + self.fail() diff --git a/test_example3.py b/test_example3.py deleted file mode 100644 index b8be0d345f45d86a0a4db4829ae796da6ff84d70..0000000000000000000000000000000000000000 --- a/test_example3.py +++ /dev/null @@ -1,10 +0,0 @@ -from unittest import TestCase - -from values import ValueDatabase, Value - -from example3 import Example3App - - -class TestExample3App(TestCase): - def test_database_access(self): - self.fail() diff --git a/values_installer.py b/values_installer.py index daad20ed819c84a24b0caeee97acbb2ca18bfee1..afb0f9c6a8d59d29a3b6c97c09cceef91a763f83 100644 --- a/values_installer.py +++ b/values_installer.py @@ -2,7 +2,11 @@ from sys import stderr from sqlalchemy.exc import SQLAlchemyError -from values import ValueDatabase, Value +from values import ValueDatabase, Persisted, Value + + +def already_has_data(session): + return any(session.query(table).first() is not None for table in Persisted.metadata.sorted_tables) def add_starter_data(session): @@ -21,9 +25,12 @@ def main(): value_database.ensure_tables_exist() print('Tables created.') session = value_database.create_session() - add_starter_data(session) - session.commit() - print('Records created.') + if already_has_data(session): + print('Not creating records because some already exist.') + else: + add_starter_data(session) + session.commit() + print('Records created.') except SQLAlchemyError as exception: print('Database setup failed!', file=stderr) print(f'Cause: {exception}', file=stderr)