diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..c18dd8d83ce --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/AUTHORS b/AUTHORS index 64b26acdc14..cbf817c9eaf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,4 +3,4 @@ Jennifer Huang <133@holbertonschool.com> Alexa Orrico <210@holbertonschool.com> -Joann Vuong <130@holbertonschool.com> +Joann Vuong <130@holbertonschool.com> diff --git a/README.md b/README.md index f1d72de6355..e41e2202e3e 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,8 @@ No known bugs at this time. ## Authors Alexa Orrico - [Github](https://github.com/alexaorrico) / [Twitter](https://twitter.com/alexa_orrico) Jennifer Huang - [Github](https://github.com/jhuang10123) / [Twitter](https://twitter.com/earthtojhuang) +Otetumo Oluwaseun Ayodele - [Github](https://https://github.com/annyauthe4) / [Twitter/X](https://x.com/annyauthe4) +Oluwafikunayomi Salu - [Github](https://github.com/fikayosalu) / [Twitter/X](https://x.com/Salufreeman) Second part of Airbnb: Joann Vuong ## License diff --git a/api/__init__.py b/api/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/api/__pycache__/__init__.cpython-38.pyc b/api/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 00000000000..e94113ecbc9 Binary files /dev/null and b/api/__pycache__/__init__.cpython-38.pyc differ diff --git a/api/v1/__init__.py b/api/v1/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/api/v1/__pycache__/__init__.cpython-38.pyc b/api/v1/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 00000000000..09d945bc602 Binary files /dev/null and b/api/v1/__pycache__/__init__.cpython-38.pyc differ diff --git a/api/v1/__pycache__/app.cpython-38.pyc b/api/v1/__pycache__/app.cpython-38.pyc new file mode 100644 index 00000000000..48d178b72d3 Binary files /dev/null and b/api/v1/__pycache__/app.cpython-38.pyc differ diff --git a/api/v1/app.py b/api/v1/app.py new file mode 100755 index 00000000000..d0745a1d667 --- /dev/null +++ b/api/v1/app.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 +"""Create a JSON 404 error page.""" + +from api.v1.views import app_views +from models import storage +from flask import Flask, jsonify, make_response +import os + + +app = Flask(__name__) +app.url_map.strict_slashes = False +app.register_blueprint(app_views) + + +@app.teardown_appcontext +def tear_down(exc): + """Cleans up after the response""" + storage.close() + + +@app.errorhandler(404) +def not_found(error): + """Returns a JSON-formatted 404 status code""" + return make_response(jsonify({'error': 'Not found'}), 404) + + +if __name__ == "__main__": + host = os.getenv("HBNB_API_HOST", "0.0.0.0") + port = int(os.getenv("HBNB_API_PORT", 5000)) + + app.run(host=host, port=port, threaded=True, debug=True) diff --git a/api/v1/views/__init__.py b/api/v1/views/__init__.py new file mode 100755 index 00000000000..fe6176d7cdc --- /dev/null +++ b/api/v1/views/__init__.py @@ -0,0 +1,12 @@ +#!/usr/bin/python3 +""" Create an Instance of Blueprint """ +from flask import Blueprint + +app_views = Blueprint("app_views", __name__, url_prefix="/api/v1") + +from api.v1.views.index import * +from api.v1.views.states import * +from api.v1.views.amenities import * +from api.v1.views.users import * +from api.v1.views.places import * +from api.v1.views.cities import * diff --git a/api/v1/views/__pycache__/__init__.cpython-38.pyc b/api/v1/views/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 00000000000..1d45d58cea7 Binary files /dev/null and b/api/v1/views/__pycache__/__init__.cpython-38.pyc differ diff --git a/api/v1/views/__pycache__/index.cpython-38.pyc b/api/v1/views/__pycache__/index.cpython-38.pyc new file mode 100644 index 00000000000..9c666a6ce6f Binary files /dev/null and b/api/v1/views/__pycache__/index.cpython-38.pyc differ diff --git a/api/v1/views/amenities.py b/api/v1/views/amenities.py new file mode 100755 index 00000000000..e0f076f6b15 --- /dev/null +++ b/api/v1/views/amenities.py @@ -0,0 +1,76 @@ +#!/usr/bin/python3 +""" Create a view for the Amenity Objects """ + + +from models import storage +from models.amenity import Amenity +from api.v1.views import app_views +from flask import jsonify, request, abort + + +@app_views.route("/amenities", methods=["GET"]) +def all_amenities(): + """ Retrieve all Amenity objects """ + amenities = storage.all(Amenity) + amenity_list = [amenity.to_dict() for amenity in amenities.values()] + return jsonify(amenity_list) + + +@app_views.route("/amenities/", methods=["GET"]) +def one_amenity(amenity_id): + """ Retrieves a Amenity Object """ + amenities = storage.get(Amenity, amenity_id) + if not amenities: + abort(404) + return jsonify(amenities.to_dict()) + + +@app_views.route("/amenities/", methods=["DELETE"]) +def delete_amenity(amenity_id): + """ Retrieves a Amenity Object """ + one_amenity = storage.get(Amenity, amenity_id) + if not one_amenity: + abort(404) + storage.delete(one_amenity) + storage.save() + return {}, 200 + + +@app_views.route("/amenities", methods=["POST"]) +def create_amenity(): + """ Create a new Amenity object """ + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + if "name" not in data: + return jsonify({"error": "Missing name"}), 400 + + new_amenity = Amenity(name=data["name"]) + + storage.new(new_amenity) + storage.save() + + return jsonify(new_amenity.to_dict()), 201 + + +@app_views.route("/amenities/", methods=["PUT"]) +def update_amenity(amenity_id): + """ Update a Amenity object """ + one_amenity = storage.get(Amenity, amenity_id) + + if not one_amenity: + return jsonify({"error": "Not found"}), 404 + + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + for key, value in data.items(): + if key not in ["id", "created_at", "updated_at"]: + setattr(one_amenity, key, value) + + storage.save() + return jsonify(one_amenity.to_dict()), 200 diff --git a/api/v1/views/cities.py b/api/v1/views/cities.py new file mode 100644 index 00000000000..34b0e53cc4c --- /dev/null +++ b/api/v1/views/cities.py @@ -0,0 +1,82 @@ +#!/usr/bin/python3 +"""Create a new view for City Objects.""" + + +from api.v1.views import app_views +from flask import jsonify, request, abort +from models import storage +from models.city import City +from models.state import State + + +@app_views.route('/states//cities', methods=['GET'], + strict_slashes=False) +def get_all_cities(state_id): + """Returns all cities by state id""" + state = storage.get(State, state_id) + if state is None: + abort(404) + return jsonify([city.to_json() for city in state.cities]) + + +@app_views.route('/cities/', methods['GET'], + strict_slashes=False) +def get_city(city_id): + """Retrieves a city object by city id""" + city = storage.get("City", str(city_id)) + if city is None: + abort(404) + return jsonify(city.to_json()) + + +@app_views.route('/cities/', methods=['DELETE'], + strict_slashes=False) +def delete_city(city_id): + """Deletes a city object by id""" + city = storage.get("City", str(city_id)) + if city is None: + abort(404) + storage.delete(city) + storage.save() + return jsonify({}), 200 + + +@app_views.route('/states//cities', methods=['POST'], + strict_slashes=False) +def create_city(state_id): + """Creates a new city object by state ID""" + state = storage.get("State", str(state_id)) + if not state: + abort(404) + try: + json_data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + if "name" not in json_data: + return jsonify({"error": "Missing name"}), 400 + new_city = City(name=json_data["name"], state_id=state_id) + storage.new(new_city) + storage.save() + + return jsonify(new_city.to_json()), 201 + + +@app_views.route('/cities/', methods=['PUT'], strict_slashes=False) +def update_city(city_id): + """Updates an existing City object""" + city = storage.get(City, city_id) + if not city: + abort(404) + try: + json_data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + ignored_keys = {"id", "state_id", "created_at", "updated_at"} + for key, value in json_data.items(): + if key not in ignored_keys: + setattr(city, key, value) + + storage.save() + + return jsonify(city.to_dict()), 200 diff --git a/api/v1/views/index.py b/api/v1/views/index.py new file mode 100755 index 00000000000..450b9c9373a --- /dev/null +++ b/api/v1/views/index.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 +""" Set up response for status code """ +from api.v1.views import app_views +from flask import jsonify +from models.amenity import Amenity +from models.city import City +from models.place import Place +from models.review import Review +from models.state import State +from models import storage +from models.user import User + + +@app_views.route("/status") +def response_status(): + """ Return status of the API """ + return jsonify({"status": "OK"}) + +@app_views.route("/api/v1/stats", method=['GET']) +def get_object_stats(): + """Retrieves the number of each object in storage by type""" + classes = { + "amenities": Amenity, + "cities": City, + "places": Place, + "reviews": Review, + "states": State, + "users": User + } + counts = {key: storage.count(value) for key, value in classes.items()} + return jsonify(counts) diff --git a/api/v1/views/places.py b/api/v1/views/places.py new file mode 100755 index 00000000000..c6b8cb0463d --- /dev/null +++ b/api/v1/views/places.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +""" Create a view for the Place Objects """ + + +from models import storage +from models.place import Place +from api.v1.views import app_views +from flask import jsonify, request, abort + + +@app_views.route("/places", methods=["GET"]) +def all_places(): + """ Retrieve all Place objects """ + places = storage.all(Place) + place_list = [place.to_dict() for place in places.values()] + return jsonify(place_list) + + +@app_views.route("/places/", methods=["GET"]) +def one_place(place_id): + """ Retrieves a Place Object """ + place = storage.get(Place, place_id) + if not place: + abort(404) + return jsonify(place.to_dict()) + + +@app_views.route("/places/", methods=["DELETE"]) +def delete_place(place_id): + """ Retrieves a Place Object """ + place = storage.get(Place, place_id) + if not place: + abort(404) + storage.delete(place) + storage.save() + return {}, 200 + + +@app_views.route("/cities/", methods=["POST"]) +def create_place(city_id): + """ Create a new Place object """ + city = storage.get(City, city_id) + if not city: + abort(404) + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + if "user_id" not in data: + return jsonify({"error": "Missing user_id"}), 400 + if "name" not in data: + return jsonify({"error": "Missing name"}), 400 + + new_place = Place(name=data["name"], user_id=data["user_id"]) + + storage.new(new_place) + storage.save() + + return jsonify(new_place.to_dict()), 201 + + +@app_views.route("/places/", methods=["PUT"]) +def update_place(place_id): + """ Update a Place object """ + one_place = storage.get(Place, place_id) + + if not one_place: + return jsonify({"error": "Not found"}), 404 + + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + for key, value in data.items(): + if key not in ["id", "created_at", "updated_at"]: + setattr(one_place, key, value) + + storage.save() + return jsonify(one_place.to_dict()), 200 diff --git a/api/v1/views/states.py b/api/v1/views/states.py new file mode 100755 index 00000000000..bb7ebeb47ee --- /dev/null +++ b/api/v1/views/states.py @@ -0,0 +1,78 @@ +#!/usr/bin/python3 +""" Create a view for the State Objects """ + + +from models import storage +from models.state import State +from api.v1.views import app_views +from flask import jsonify, request, abort + + +@app_views.route("/states", methods=["GET"]) +def all_states(): + """ Retrieve all State objects """ + states = storage.all(State) + state_list = [state.to_dict() for state in states.values()] + return jsonify(state_list) + + +@app_views.route("/states/", methods=["GET"]) +def one_state(state_id): + """ Retrieves a State Object """ + states = storage.all(State) + state_list = [state.to_dict() for state in states.values()] + one_state = [state for state in state_list if state["id"] == state_id] + if len(one_state) == 0: + abort(404) + return jsonify(one_state[0]) + + +@app_views.route("/states/", methods=["DELETE"]) +def delete_state(state_id): + """ Retrieves a State Object """ + one_state = storage.get(State, state_id) + if not one_state: + abort(404) + storage.delete(one_state) + storage.save() + return {}, 200 + + +@app_views.route("/states", methods=["POST"]) +def create_state(): + """ Create a new State object """ + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + if "name" not in data: + return jsonify({"error": "Missing name"}), 400 + + new_state = State(name=data["name"]) + + storage.new(new_state) + storage.save() + + return jsonify(new_state.to_dict()), 201 + + +@app_views.route("/states/", methods=["PUT"]) +def update_state(state_id): + """ Update a State object """ + one_state = storage.get(State, state_id) + + if not one_state: + return jsonify({"error": "Not found"}), 404 + + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + for key, value in data.items(): + if key not in ["id", "created_at", "updated_at"]: + setattr(one_state, key, value) + + storage.save() + return jsonify(one_state.to_dict()), 200 diff --git a/api/v1/views/users.py b/api/v1/views/users.py new file mode 100755 index 00000000000..ada3764917c --- /dev/null +++ b/api/v1/views/users.py @@ -0,0 +1,78 @@ +#!/usr/bin/python3 +""" Create a view for the User Objects """ + + +from models import storage +from models.user import User +from api.v1.views import app_views +from flask import jsonify, request, abort + + +@app_views.route("/users", methods=["GET"]) +def all_users(): + """ Retrieve all User objects """ + users = storage.all(User) + user_list = [user.to_dict() for user in users.values()] + return jsonify(user_list) + + +@app_views.route("/users/", methods=["GET"]) +def one_user(user_id): + """ Retrieves a User Object """ + user = storage.get(User, user_id) + if not user: + abort(404) + return jsonify(user.to_dict()) + + +@app_views.route("/users/", methods=["DELETE"]) +def delete_user(user_id): + """ Retrieves a User Object """ + user = storage.get(User, user_id) + if not user: + abort(404) + storage.delete(user) + storage.save() + return {}, 200 + + +@app_views.route("/users", methods=["POST"]) +def create_user(): + """ Create a new User object """ + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + if "email" not in data: + return jsonify({"error": "Missing email"}), 400 + if "password" not in data: + return jsonify({"error": "Missing password"}), 400 + + new_user = User(email=data["email"], password=data["password"]) + + storage.new(new_user) + storage.save() + + return jsonify(new_user.to_dict()), 201 + + +@app_views.route("/users/", methods=["PUT"]) +def update_user(user_id): + """ Update a User object """ + one_user = storage.get(User, user_id) + + if not one_user: + return jsonify({"error": "Not found"}), 404 + + try: + data = request.get_json() + except Exception: + return jsonify({"error": "Not a JSON"}), 400 + + for key, value in data.items(): + if key not in ["id", "created_at", "updated_at"]: + setattr(one_user, key, value) + + storage.save() + return jsonify(one_user.to_dict()), 200 diff --git a/models/__pycache__/__init__.cpython-310.pyc b/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000000..129018d38ed Binary files /dev/null and b/models/__pycache__/__init__.cpython-310.pyc differ diff --git a/models/__pycache__/__init__.cpython-38.pyc b/models/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 00000000000..f5aeba4a416 Binary files /dev/null and b/models/__pycache__/__init__.cpython-38.pyc differ diff --git a/models/__pycache__/amenity.cpython-310.pyc b/models/__pycache__/amenity.cpython-310.pyc new file mode 100644 index 00000000000..8fa6b61c460 Binary files /dev/null and b/models/__pycache__/amenity.cpython-310.pyc differ diff --git a/models/__pycache__/amenity.cpython-38.pyc b/models/__pycache__/amenity.cpython-38.pyc new file mode 100644 index 00000000000..8028f2efbd6 Binary files /dev/null and b/models/__pycache__/amenity.cpython-38.pyc differ diff --git a/models/__pycache__/base_model.cpython-310.pyc b/models/__pycache__/base_model.cpython-310.pyc new file mode 100644 index 00000000000..9257ca5254a Binary files /dev/null and b/models/__pycache__/base_model.cpython-310.pyc differ diff --git a/models/__pycache__/base_model.cpython-38.pyc b/models/__pycache__/base_model.cpython-38.pyc new file mode 100644 index 00000000000..6b34e19215d Binary files /dev/null and b/models/__pycache__/base_model.cpython-38.pyc differ diff --git a/models/__pycache__/city.cpython-310.pyc b/models/__pycache__/city.cpython-310.pyc new file mode 100644 index 00000000000..4783c4a70b5 Binary files /dev/null and b/models/__pycache__/city.cpython-310.pyc differ diff --git a/models/__pycache__/city.cpython-38.pyc b/models/__pycache__/city.cpython-38.pyc new file mode 100644 index 00000000000..4fa5fa67370 Binary files /dev/null and b/models/__pycache__/city.cpython-38.pyc differ diff --git a/models/__pycache__/place.cpython-310.pyc b/models/__pycache__/place.cpython-310.pyc new file mode 100644 index 00000000000..7d22a08210f Binary files /dev/null and b/models/__pycache__/place.cpython-310.pyc differ diff --git a/models/__pycache__/place.cpython-38.pyc b/models/__pycache__/place.cpython-38.pyc new file mode 100644 index 00000000000..67a200d5690 Binary files /dev/null and b/models/__pycache__/place.cpython-38.pyc differ diff --git a/models/__pycache__/review.cpython-310.pyc b/models/__pycache__/review.cpython-310.pyc new file mode 100644 index 00000000000..5da40625caa Binary files /dev/null and b/models/__pycache__/review.cpython-310.pyc differ diff --git a/models/__pycache__/review.cpython-38.pyc b/models/__pycache__/review.cpython-38.pyc new file mode 100644 index 00000000000..65cd88231d8 Binary files /dev/null and b/models/__pycache__/review.cpython-38.pyc differ diff --git a/models/__pycache__/state.cpython-310.pyc b/models/__pycache__/state.cpython-310.pyc new file mode 100644 index 00000000000..253803ace6c Binary files /dev/null and b/models/__pycache__/state.cpython-310.pyc differ diff --git a/models/__pycache__/state.cpython-38.pyc b/models/__pycache__/state.cpython-38.pyc new file mode 100644 index 00000000000..45d1a3724da Binary files /dev/null and b/models/__pycache__/state.cpython-38.pyc differ diff --git a/models/__pycache__/user.cpython-310.pyc b/models/__pycache__/user.cpython-310.pyc new file mode 100644 index 00000000000..67459473aa3 Binary files /dev/null and b/models/__pycache__/user.cpython-310.pyc differ diff --git a/models/__pycache__/user.cpython-38.pyc b/models/__pycache__/user.cpython-38.pyc new file mode 100644 index 00000000000..7d415126f35 Binary files /dev/null and b/models/__pycache__/user.cpython-38.pyc differ diff --git a/models/engine/__pycache__/__init__.cpython-310.pyc b/models/engine/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000000..57c3d0f18f7 Binary files /dev/null and b/models/engine/__pycache__/__init__.cpython-310.pyc differ diff --git a/models/engine/__pycache__/__init__.cpython-38.pyc b/models/engine/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 00000000000..7921daa7786 Binary files /dev/null and b/models/engine/__pycache__/__init__.cpython-38.pyc differ diff --git a/models/engine/__pycache__/db_storage.cpython-310.pyc b/models/engine/__pycache__/db_storage.cpython-310.pyc new file mode 100644 index 00000000000..2e57932c679 Binary files /dev/null and b/models/engine/__pycache__/db_storage.cpython-310.pyc differ diff --git a/models/engine/__pycache__/db_storage.cpython-38.pyc b/models/engine/__pycache__/db_storage.cpython-38.pyc new file mode 100644 index 00000000000..1783a64f8dd Binary files /dev/null and b/models/engine/__pycache__/db_storage.cpython-38.pyc differ diff --git a/models/engine/__pycache__/file_storage.cpython-310.pyc b/models/engine/__pycache__/file_storage.cpython-310.pyc new file mode 100644 index 00000000000..aa817c6a3c2 Binary files /dev/null and b/models/engine/__pycache__/file_storage.cpython-310.pyc differ diff --git a/models/engine/db_storage.py b/models/engine/db_storage.py index b8e7d291e6f..1c8f63e61f7 100755 --- a/models/engine/db_storage.py +++ b/models/engine/db_storage.py @@ -74,3 +74,28 @@ def reload(self): def close(self): """call remove() method on the private session attribute""" self.__session.remove() + + def get(self, cls, id): + """Retrieve one object by class and ID.""" + if cls is None or id is None: + return None + # Convert class name string to class object + if isinstance(cls, str): + cls = classes.get(cls) + + # Check if class name is in classes list + if cls not in classes.values(): + return None + return self.__session.query(cls).filter_by(id=id).first() + + def count(self, cls=None): + """Counts the number of objects in storage.""" + if cls is None: + return sum(self.count(c) for c in classes.values()) + + # Convert cls into obj if str is given + if isinstance(cls, str): + cls = classes.get(cls) + if cls not in classes.values(): + return 0 + return self.__session.query(cls).count() diff --git a/models/engine/file_storage.py b/models/engine/file_storage.py index c8cb8c1764d..56d76b62a69 100755 --- a/models/engine/file_storage.py +++ b/models/engine/file_storage.py @@ -68,3 +68,23 @@ def delete(self, obj=None): def close(self): """call reload() method for deserializing the JSON file to objects""" self.reload() + + def get(self, cls, id): + if cls is None or id is None: + return None + if isinstance(cls, str): + cls = classes.get(cls) + if cls not in classes.values(): + return None + key = cls.__name__ + '.' + id + return self.__objects.get(key) + + def count(self, cls=None): + """Counts the number of objects in storage.""" + if cls is None: + return len(self.__objects) + if isinstance(cls, str): + cls = classes.get(cls) + if cls not in classes.values(): + return 0 + return len({k: v for k, v in self.__objects.items() if isinstance(v, cls)}) diff --git a/test.py b/test.py new file mode 100755 index 00000000000..1afebdf9b08 --- /dev/null +++ b/test.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 +""" Create a view for the State Objects """ + + +from models import storage +from models.state import State +from api.v1.views import app_views +from flask import jsonify + + +def all_states(): + states = storage.all(State) + state_list = [state.to_dict() for state in states.values()] # Convert each object to dict + return jsonify(state_list) # Return JSON response diff --git a/test_get_count.py b/test_get_count.py new file mode 100644 index 00000000000..18194dfce69 --- /dev/null +++ b/test_get_count.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3 +""" Test .get() and .count() methods +""" +from models import storage +from models.state import State + +print("All objects: {}".format(storage.count())) +print("State objects: {}".format(storage.count(State))) + +first_state_id = list(storage.all(State).values())[0].id +print("First state: {}".format(storage.get(State, first_state_id))) diff --git a/tests/__pycache__/test_console.cpython-310.pyc b/tests/__pycache__/test_console.cpython-310.pyc new file mode 100644 index 00000000000..c6e6b3bd472 Binary files /dev/null and b/tests/__pycache__/test_console.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/__init__.cpython-310.pyc b/tests/test_models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000000..5d0e3f56c87 Binary files /dev/null and b/tests/test_models/__pycache__/__init__.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_amenity.cpython-310.pyc b/tests/test_models/__pycache__/test_amenity.cpython-310.pyc new file mode 100644 index 00000000000..971993f9135 Binary files /dev/null and b/tests/test_models/__pycache__/test_amenity.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_base_model.cpython-310.pyc b/tests/test_models/__pycache__/test_base_model.cpython-310.pyc new file mode 100644 index 00000000000..810509cf033 Binary files /dev/null and b/tests/test_models/__pycache__/test_base_model.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_city.cpython-310.pyc b/tests/test_models/__pycache__/test_city.cpython-310.pyc new file mode 100644 index 00000000000..9fd99ada919 Binary files /dev/null and b/tests/test_models/__pycache__/test_city.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_place.cpython-310.pyc b/tests/test_models/__pycache__/test_place.cpython-310.pyc new file mode 100644 index 00000000000..549605fe7be Binary files /dev/null and b/tests/test_models/__pycache__/test_place.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_review.cpython-310.pyc b/tests/test_models/__pycache__/test_review.cpython-310.pyc new file mode 100644 index 00000000000..ab70c316622 Binary files /dev/null and b/tests/test_models/__pycache__/test_review.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_state.cpython-310.pyc b/tests/test_models/__pycache__/test_state.cpython-310.pyc new file mode 100644 index 00000000000..296d82f67c2 Binary files /dev/null and b/tests/test_models/__pycache__/test_state.cpython-310.pyc differ diff --git a/tests/test_models/__pycache__/test_user.cpython-310.pyc b/tests/test_models/__pycache__/test_user.cpython-310.pyc new file mode 100644 index 00000000000..6f9f66907b7 Binary files /dev/null and b/tests/test_models/__pycache__/test_user.cpython-310.pyc differ diff --git a/tests/test_models/test_engine/__pycache__/__init__.cpython-310.pyc b/tests/test_models/test_engine/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000000..2d90cb1e4e0 Binary files /dev/null and b/tests/test_models/test_engine/__pycache__/__init__.cpython-310.pyc differ diff --git a/tests/test_models/test_engine/__pycache__/test_db_storage.cpython-310.pyc b/tests/test_models/test_engine/__pycache__/test_db_storage.cpython-310.pyc new file mode 100644 index 00000000000..5defecf9bdb Binary files /dev/null and b/tests/test_models/test_engine/__pycache__/test_db_storage.cpython-310.pyc differ diff --git a/tests/test_models/test_engine/__pycache__/test_file_storage.cpython-310.pyc b/tests/test_models/test_engine/__pycache__/test_file_storage.cpython-310.pyc new file mode 100644 index 00000000000..07906f577e8 Binary files /dev/null and b/tests/test_models/test_engine/__pycache__/test_file_storage.cpython-310.pyc differ diff --git a/tests/test_models/test_engine/test_db_storage.py b/tests/test_models/test_engine/test_db_storage.py index 766e625b5af..a29475fa22c 100755 --- a/tests/test_models/test_engine/test_db_storage.py +++ b/tests/test_models/test_engine/test_db_storage.py @@ -41,7 +41,7 @@ def test_pep8_conformance_test_db_storage(self): """Test tests/test_models/test_db_storage.py conforms to PEP8.""" pep8s = pep8.StyleGuide(quiet=True) result = pep8s.check_files(['tests/test_models/test_engine/\ -test_db_storage.py']) + test_db_storage.py']) self.assertEqual(result.total_errors, 0, "Found code style errors (and warnings).") @@ -68,21 +68,93 @@ def test_dbs_func_docstrings(self): "{:s} method needs a docstring".format(func[0])) -class TestFileStorage(unittest.TestCase): - """Test the FileStorage class""" +class TestDBStorage(unittest.TestCase): + """Test the DBStorage class""" + + @classmethod + def setUpClass(cls): + """Set up a test instance""" + cls.storage = DBStorage() + cls.storage.reload() + + # Create test objecs + cls.user = User(email="test@example.com", password="test") + cls.state = State(name="California") + + cls.storage.new(cls.user) + cls.storage.new(cls.state) + cls.storage.save() + + @classmethod + def tearDownClass(cls): + """Clean up test objects""" + cls.storage.delete(cls.user) + cls.storage.delete(cls.state) + cls.storage.save() + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_all_returns_dict(self): """Test that all returns a dictionaty""" - self.assertIs(type(models.storage.all()), dict) + self.assertIsInstance(models.storage.all(), dict) @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_all_no_class(self): """Test that all returns all rows when no class is passed""" + all_objs = model.storage.all() + self.assertGreaterEqual(len(all_objs), 2) @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_new(self): """test that new adds an object to the database""" + new_city = City(name="New York") + models.storage.new(new_city) + models.storage.save() + self.assertIn(f"City.{new_city.id}", models.storage.all()) @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_save(self): - """Test that save properly saves objects to file.json""" + """Test that save properly saves objects to database""" + new_place = Place(name="Cool Place") + models.storage.new(new_place) + models.storage.save() + self.assertIn(f"Place.{new_place.id}", models.storage.all()) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_get_existing_object(self): + """Test get method retrieves an existing object""" + user = models.storage.get(User, self.user.id) + self.assertIsNotNone(user) + self.assertEqual(user.id, self.user.id) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_get_nonexistent_object(self): + """Test get method returns None for a non-existent object""" + self.assertIsNone(models.storage.get(User, "nonexistent_id")) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_get_invalid_class(self): + """Test get method returns None for an invalid class""" + self.assertIsNone(models.storage.get("AClass", "1234")) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_count_all(self): + """Test count method returns the total number of objects""" + initial_count = models.storage.count() + self.assertGreaterEqual(initial_count, 2) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_count_specific_class(self): + """Test count method returns correct count for a given class""" + user_count = models.storage.count(User) + state_count = models.storage.count(State) + self.assertGreaterEqual(user_count, 1) + self.assertGreaterEqual(state_count, 1) + + @unittest.skipIf(models.storage_t != 'db', "not testing db storage") + def test_count_invalid_class(self): + """Test count method returns 0 for an invalid class""" + self.assertEqual(models.storage.count("InvalidClass"), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_models/test_engine/test_file_storage.py b/tests/test_models/test_engine/test_file_storage.py index 1474a34fec0..95c729019dd 100755 --- a/tests/test_models/test_engine/test_file_storage.py +++ b/tests/test_models/test_engine/test_file_storage.py @@ -41,7 +41,7 @@ def test_pep8_conformance_test_file_storage(self): """Test tests/test_models/test_file_storage.py conforms to PEP8.""" pep8s = pep8.StyleGuide(quiet=True) result = pep8s.check_files(['tests/test_models/test_engine/\ -test_file_storage.py']) + test_file_storage.py']) self.assertEqual(result.total_errors, 0, "Found code style errors (and warnings).") @@ -70,18 +70,37 @@ def test_fs_func_docstrings(self): class TestFileStorage(unittest.TestCase): """Test the FileStorage class""" + @classmethod + def setUpClass(cls): + """Set up test instance""" + cls.storage = FileStorage() + + # Create test objects + cls.user = User(email="test@example.com", password="test") + cls.state = State(name="California") + + cls.storage.new(cls.user) + cls.storage.new(cls.state) + cls.storage.save() + + @classmethod + def tearDownClass(cls): + """Clean up test objects""" + try: + os.remove("file.json") + except FileNotFoundError: + pass + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_all_returns_dict(self): """Test that all returns the FileStorage.__objects attr""" - storage = FileStorage() - new_dict = storage.all() + new_dict = self.storage.all() self.assertEqual(type(new_dict), dict) - self.assertIs(new_dict, storage._FileStorage__objects) + self.assertIs(new_dict, self.storage._FileStorage__objects) @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_new(self): """test that new adds an object to the FileStorage.__objects attr""" - storage = FileStorage() save = FileStorage._FileStorage__objects FileStorage._FileStorage__objects = {} test_dict = {} @@ -89,15 +108,14 @@ def test_new(self): with self.subTest(key=key, value=value): instance = value() instance_key = instance.__class__.__name__ + "." + instance.id - storage.new(instance) + self.storage.new(instance) test_dict[instance_key] = instance - self.assertEqual(test_dict, storage._FileStorage__objects) + self.assertEqual(test_dict, self.storage._FileStorage__objects) FileStorage._FileStorage__objects = save @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_save(self): """Test that save properly saves objects to file.json""" - storage = FileStorage() new_dict = {} for key, value in classes.items(): instance = value() @@ -105,7 +123,7 @@ def test_save(self): new_dict[instance_key] = instance save = FileStorage._FileStorage__objects FileStorage._FileStorage__objects = new_dict - storage.save() + self.storage.save() FileStorage._FileStorage__objects = save for key, value in new_dict.items(): new_dict[key] = value.to_dict() @@ -113,3 +131,43 @@ def test_save(self): with open("file.json", "r") as f: js = f.read() self.assertEqual(json.loads(string), json.loads(js)) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_get_existing_object(self): + """Test get method retrieves an existing object""" + user = self.storage.get(User, self.user.id) + self.assertIsNotNone(user) + self.assertEqual(user.id, self.user.id) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_get_nonexistent_object(self): + """Test get method using non-existent object""" + self.assertIsNone(self.storage.get(User, "nonexistent_id")) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_get_invalid_class(self): + """Test get method returns None for an invalid class""" + self.assertIsNone(self.storage.get("InvalidClass", "1234")) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_count_all(self): + """Test count method returns the total number of objects""" + initial_count = self.storage.count() + self.assertGreaterEqual(initial_count, 2) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_count_specific_class(self): + """Test count method returns correct count for a given class""" + user_count = self.storage.count(User) + state_count = self.storage.count(State) + self.assertGreaterEqual(user_count, 1) + self.assertGreaterEqual(state_count, 1) + + @unittest.skipIf(models.storage_t == 'db', "not testing file storage") + def test_count_invalid_class(self): + """Test count method returns 0 for an invalid class""" + self.assertEqual(self.storage.count("InvalidClass"), 0) + + +if __name__ == "__main__": + unittest.main()