From 90acfc0e85fb298d4c0e35371c3022650510dac4 Mon Sep 17 00:00:00 2001 From: peyanshin Date: Sun, 15 Mar 2026 02:48:23 +0300 Subject: [PATCH] Add files via upload --- htmlcov/class_index.html | 221 ++++++ htmlcov/coverage_html_cb_188fc9a4.js | 735 ++++++++++++++++++ htmlcov/favicon_32_cb_c827f16f.png | Bin 0 -> 1732 bytes htmlcov/function_index.html | 361 +++++++++ htmlcov/index.html | 171 ++++ htmlcov/keybd_closed_cb_900cfef5.png | Bin 0 -> 9004 bytes htmlcov/status.json | 1 + htmlcov/style_cb_5c747636.css | 389 +++++++++ htmlcov/z_c68eb0c7512457e4___init___py.html | 97 +++ htmlcov/z_c68eb0c7512457e4_bun_py.html | 112 +++ htmlcov/z_c68eb0c7512457e4_burger_py.html | 145 ++++ htmlcov/z_c68eb0c7512457e4_database_py.html | 130 ++++ htmlcov/z_c68eb0c7512457e4_ingredient_py.html | 117 +++ ..._c68eb0c7512457e4_ingredient_types_py.html | 104 +++ htmlcov/z_c68eb0c7512457e4_praktikum_py.html | 138 ++++ praktikum/README.md | 24 + praktikum/__init__.py | 0 .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 130 bytes praktikum/__pycache__/bun.cpython-314.pyc | Bin 0 -> 1545 bytes praktikum/__pycache__/burger.cpython-314.pyc | Bin 0 -> 4136 bytes .../__pycache__/ingredient.cpython-314.pyc | Bin 0 -> 1994 bytes praktikum/bun.py | 15 + praktikum/burger.py | 48 ++ praktikum/database.py | 33 + praktikum/ingredient.py | 20 + praktikum/ingredient_types.py | 7 + praktikum/praktikum.py | 41 + .../conftest.cpython-314-pytest-8.3.3.pyc | Bin 0 -> 1626 bytes .../test_burger.cpython-314-pytest-8.3.3.pyc | Bin 0 -> 41208 bytes tests/conftest.py | 33 + tests/test_burger.py | 236 ++++++ 31 files changed, 3178 insertions(+) create mode 100644 htmlcov/class_index.html create mode 100644 htmlcov/coverage_html_cb_188fc9a4.js create mode 100644 htmlcov/favicon_32_cb_c827f16f.png create mode 100644 htmlcov/function_index.html create mode 100644 htmlcov/index.html create mode 100644 htmlcov/keybd_closed_cb_900cfef5.png create mode 100644 htmlcov/status.json create mode 100644 htmlcov/style_cb_5c747636.css create mode 100644 htmlcov/z_c68eb0c7512457e4___init___py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_bun_py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_burger_py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_database_py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_ingredient_py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_ingredient_types_py.html create mode 100644 htmlcov/z_c68eb0c7512457e4_praktikum_py.html create mode 100644 praktikum/README.md create mode 100644 praktikum/__init__.py create mode 100644 praktikum/__pycache__/__init__.cpython-314.pyc create mode 100644 praktikum/__pycache__/bun.cpython-314.pyc create mode 100644 praktikum/__pycache__/burger.cpython-314.pyc create mode 100644 praktikum/__pycache__/ingredient.cpython-314.pyc create mode 100644 praktikum/bun.py create mode 100644 praktikum/burger.py create mode 100644 praktikum/database.py create mode 100644 praktikum/ingredient.py create mode 100644 praktikum/ingredient_types.py create mode 100644 praktikum/praktikum.py create mode 100644 tests/__pycache__/conftest.cpython-314-pytest-8.3.3.pyc create mode 100644 tests/__pycache__/test_burger.cpython-314-pytest-8.3.3.pyc create mode 100644 tests/conftest.py create mode 100644 tests/test_burger.py diff --git a/htmlcov/class_index.html b/htmlcov/class_index.html new file mode 100644 index 000000000..918a508fe --- /dev/null +++ b/htmlcov/class_index.html @@ -0,0 +1,221 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 52% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fileclass statementsmissingexcluded coverage
praktikum \ __init__.py(no class) 000 100%
praktikum \ bun.pyBun 400 100%
praktikum \ bun.py(no class) 400 100%
praktikum \ burger.pyBurger 1600 100%
praktikum \ burger.py(no class) 1100 100%
praktikum \ database.pyDatabase 13130 0%
praktikum \ database.py(no class) 880 0%
praktikum \ ingredient.pyIngredient 600 100%
praktikum \ ingredient.py(no class) 500 100%
praktikum \ ingredient_types.py(no class) 220 0%
praktikum \ praktikum.py(no class) 20200 0%
Total  89430 52%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/htmlcov/coverage_html_cb_188fc9a4.js b/htmlcov/coverage_html_cb_188fc9a4.js new file mode 100644 index 000000000..ebdc077fd --- /dev/null +++ b/htmlcov/coverage_html_cb_188fc9a4.js @@ -0,0 +1,735 @@ +// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +// For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt + +// Coverage.py HTML report browser code. +/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ +/*global coverage: true, document, window, $ */ + +coverage = {}; + +// General helpers +function debounce(callback, wait) { + let timeoutId = null; + return function(...args) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + callback.apply(this, args); + }, wait); + }; +}; + +function checkVisible(element) { + const rect = element.getBoundingClientRect(); + const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight); + const viewTop = 30; + return !(rect.bottom < viewTop || rect.top >= viewBottom); +} + +function on_click(sel, fn) { + const elt = document.querySelector(sel); + if (elt) { + elt.addEventListener("click", fn); + } +} + +// Helpers for table sorting +function getCellValue(row, column = 0) { + const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.childElementCount == 1) { + var child = cell.firstElementChild; + if (child.tagName === "A") { + child = child.firstElementChild; + } + if (child instanceof HTMLDataElement && child.value) { + return child.value; + } + } + return cell.innerText || cell.textContent; +} + +function rowComparator(rowA, rowB, column = 0) { + let valueA = getCellValue(rowA, column); + let valueB = getCellValue(rowB, column); + if (!isNaN(valueA) && !isNaN(valueB)) { + return valueA - valueB; + } + return valueA.localeCompare(valueB, undefined, {numeric: true}); +} + +function sortColumn(th) { + // Get the current sorting direction of the selected header, + // clear state on other headers and then set the new sorting direction. + const currentSortOrder = th.getAttribute("aria-sort"); + [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none")); + var direction; + if (currentSortOrder === "none") { + direction = th.dataset.defaultSortOrder || "ascending"; + } + else if (currentSortOrder === "ascending") { + direction = "descending"; + } + else { + direction = "ascending"; + } + th.setAttribute("aria-sort", direction); + + const column = [...th.parentElement.cells].indexOf(th) + + // Sort all rows and afterwards append them in order to move them in the DOM. + Array.from(th.closest("table").querySelectorAll("tbody tr")) + .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1)) + .forEach(tr => tr.parentElement.appendChild(tr)); + + // Save the sort order for next time. + if (th.id !== "region") { + let th_id = "file"; // Sort by file if we don't have a column id + let current_direction = direction; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)) + } + localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({ + "th_id": th.id, + "direction": current_direction + })); + if (th.id !== th_id || document.getElementById("region")) { + // Sort column has changed, unset sorting by function or class. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": false, + "region_direction": current_direction + })); + } + } + else { + // Sort column has changed to by function or class, remember that. + localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({ + "by_region": true, + "region_direction": direction + })); + } +} + +// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key. +coverage.assign_shortkeys = function () { + document.querySelectorAll("[data-shortcut]").forEach(element => { + document.addEventListener("keypress", event => { + if (event.target.tagName.toLowerCase() === "input") { + return; // ignore keypress from search filter + } + if (event.key === element.dataset.shortcut) { + element.click(); + } + }); + }); +}; + +// Create the events for the filter box. +coverage.wire_up_filter = function () { + // Populate the filter and hide100 inputs if there are saved values for them. + const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE); + if (saved_filter_value) { + document.getElementById("filter").value = saved_filter_value; + } + const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE); + if (saved_hide100_value) { + document.getElementById("hide100").checked = JSON.parse(saved_hide100_value); + } + + // Cache elements. + const table = document.querySelector("table.index"); + const table_body_rows = table.querySelectorAll("tbody tr"); + const no_rows = document.getElementById("no_rows"); + + const footer = table.tFoot.rows[0]; + const ratio_columns = Array.from(footer.cells).map(cell => Boolean(cell.dataset.ratio)); + + // Observe filter keyevents. + const filter_handler = (event => { + // Keep running total of each metric, first index contains number of shown rows + const totals = ratio_columns.map( + is_ratio => is_ratio ? {"numer": 0, "denom": 0} : 0 + ); + + var text = document.getElementById("filter").value; + // Store filter value + localStorage.setItem(coverage.FILTER_STORAGE, text); + const casefold = (text === text.toLowerCase()); + const hide100 = document.getElementById("hide100").checked; + // Store hide value. + localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100)); + + // Hide / show elements. + table_body_rows.forEach(row => { + var show = false; + // Check the text filter. + for (let column = 0; column < totals.length; column++) { + cell = row.cells[column]; + if (cell.classList.contains("name")) { + var celltext = cell.textContent; + if (casefold) { + celltext = celltext.toLowerCase(); + } + if (celltext.includes(text)) { + show = true; + } + } + } + + // Check the "hide covered" filter. + if (show && hide100) { + const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" "); + show = (numer !== denom); + } + + if (!show) { + // hide + row.classList.add("hidden"); + return; + } + + // show + row.classList.remove("hidden"); + totals[0]++; + + for (let column = 0; column < totals.length; column++) { + // Accumulate dynamic totals + cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.matches(".name, .spacer")) { + continue; + } + if (ratio_columns[column] && cell.dataset.ratio) { + // Column stores a ratio + const [numer, denom] = cell.dataset.ratio.split(" "); + totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection + totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection + } + else { + totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection + } + } + }); + + // Show placeholder if no rows will be displayed. + if (!totals[0]) { + // Show placeholder, hide table. + no_rows.style.display = "block"; + table.style.display = "none"; + return; + } + + // Hide placeholder, show table. + no_rows.style.display = null; + table.style.display = null; + + // Calculate new dynamic sum values based on visible rows. + for (let column = 0; column < totals.length; column++) { + // Get footer cell element. + const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection + if (cell.matches(".name, .spacer")) { + continue; + } + + // Set value into dynamic footer cell element. + if (ratio_columns[column]) { + // Percentage column uses the numerator and denominator, + // and adapts to the number of decimal places. + const match = /\.([0-9]+)/.exec(cell.textContent); + const places = match ? match[1].length : 0; + const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection + cell.dataset.ratio = `${numer} ${denom}`; + // Check denom to prevent NaN if filtered files contain no statements + cell.textContent = denom + ? `${(numer * 100 / denom).toFixed(places)}%` + : `${(100).toFixed(places)}%`; + } + else { + cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection + } + } + }); + + document.getElementById("filter").addEventListener("input", debounce(filter_handler)); + document.getElementById("hide100").addEventListener("input", debounce(filter_handler)); + + // Trigger change event on setup, to force filter on page refresh + // (filter value may still be present). + document.getElementById("filter").dispatchEvent(new Event("input")); + document.getElementById("hide100").dispatchEvent(new Event("input")); +}; +coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE"; +coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE"; + +// Set up the click-to-sort columns. +coverage.wire_up_sorting = function () { + document.querySelectorAll("[data-sortable] th[aria-sort]").forEach( + th => th.addEventListener("click", e => sortColumn(e.target)) + ); + + // Look for a localStorage item containing previous sort settings: + let th_id = "file", direction = "ascending"; + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + if (stored_list) { + ({th_id, direction} = JSON.parse(stored_list)); + } + let by_region = false, region_direction = "ascending"; + const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION); + if (sorted_by_region) { + ({ + by_region, + region_direction + } = JSON.parse(sorted_by_region)); + } + + const region_id = "region"; + if (by_region && document.getElementById(region_id)) { + direction = region_direction; + } + // If we are in a page that has a column with id of "region", sort on + // it if the last sort was by function or class. + let th; + if (document.getElementById(region_id)) { + th = document.getElementById(by_region ? region_id : th_id); + } + else { + th = document.getElementById(th_id); + } + th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending"); + th.click() +}; + +coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2"; +coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION"; + +// Loaded on index.html +coverage.index_ready = function () { + coverage.assign_shortkeys(); + coverage.wire_up_filter(); + coverage.wire_up_sorting(); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + + on_click(".button_show_hide_help", coverage.show_hide_help); +}; + +// -- pyfile stuff -- + +coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; + +coverage.pyfile_ready = function () { + // If we're directed to a particular line number, highlight the line. + var frag = location.hash; + if (frag.length > 2 && frag[1] === "t") { + document.querySelector(frag).closest(".n").classList.add("highlight"); + coverage.set_sel(parseInt(frag.substr(2), 10)); + } + else { + coverage.set_sel(0); + } + + on_click(".button_toggle_run", coverage.toggle_lines); + on_click(".button_toggle_mis", coverage.toggle_lines); + on_click(".button_toggle_exc", coverage.toggle_lines); + on_click(".button_toggle_par", coverage.toggle_lines); + + on_click(".button_next_chunk", coverage.to_next_chunk_nicely); + on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely); + on_click(".button_top_of_page", coverage.to_top); + on_click(".button_first_chunk", coverage.to_first_chunk); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + on_click(".button_to_index", coverage.to_index); + + on_click(".button_show_hide_help", coverage.show_hide_help); + + coverage.filters = undefined; + try { + coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); + } catch(err) {} + + if (coverage.filters) { + coverage.filters = JSON.parse(coverage.filters); + } + else { + coverage.filters = {run: false, exc: true, mis: true, par: true}; + } + + for (cls in coverage.filters) { + coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection + } + + coverage.assign_shortkeys(); + coverage.init_scroll_markers(); + coverage.wire_up_sticky_header(); + + document.querySelectorAll("[id^=ctxs]").forEach( + cbox => cbox.addEventListener("click", coverage.expand_contexts) + ); + + // Rebuild scroll markers when the window height changes. + window.addEventListener("resize", coverage.build_scroll_markers); +}; + +coverage.toggle_lines = function (event) { + const btn = event.target.closest("button"); + const category = btn.value + const show = !btn.classList.contains("show_" + category); + coverage.set_line_visibilty(category, show); + coverage.build_scroll_markers(); + coverage.filters[category] = show; + try { + localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); + } catch(err) {} +}; + +coverage.set_line_visibilty = function (category, should_show) { + const cls = "show_" + category; + const btn = document.querySelector(".button_toggle_" + category); + if (btn) { + if (should_show) { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls)); + btn.classList.add(cls); + } + else { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls)); + btn.classList.remove(cls); + } + } +}; + +// Return the nth line div. +coverage.line_elt = function (n) { + return document.getElementById("t" + n)?.closest("p"); +}; + +// Set the selection. b and e are line numbers. +coverage.set_sel = function (b, e) { + // The first line selected. + coverage.sel_begin = b; + // The next line not selected. + coverage.sel_end = (e === undefined) ? b+1 : e; +}; + +coverage.to_top = function () { + coverage.set_sel(0, 1); + coverage.scroll_window(0); +}; + +coverage.to_first_chunk = function () { + coverage.set_sel(0, 1); + coverage.to_next_chunk(); +}; + +coverage.to_prev_file = function () { + window.location = document.getElementById("prevFileLink").href; +} + +coverage.to_next_file = function () { + window.location = document.getElementById("nextFileLink").href; +} + +coverage.to_index = function () { + location.href = document.getElementById("indexLink").href; +} + +coverage.show_hide_help = function () { + const helpCheck = document.getElementById("help_panel_state") + helpCheck.checked = !helpCheck.checked; +} + +// Return a string indicating what kind of chunk this line belongs to, +// or null if not a chunk. +coverage.chunk_indicator = function (line_elt) { + const classes = line_elt?.className; + if (!classes) { + return null; + } + const match = classes.match(/\bshow_\w+\b/); + if (!match) { + return null; + } + return match[0]; +}; + +coverage.to_next_chunk = function () { + const c = coverage; + + // Find the start of the next colored chunk. + var probe = c.sel_end; + var chunk_indicator, probe_line; + while (true) { + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + if (chunk_indicator) { + break; + } + probe++; + } + + // There's a next chunk, `probe` points to it. + var begin = probe; + + // Find the end of this chunk. + var next_indicator = chunk_indicator; + while (next_indicator === chunk_indicator) { + probe++; + probe_line = c.line_elt(probe); + next_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(begin, probe); + c.show_selection(); +}; + +coverage.to_prev_chunk = function () { + const c = coverage; + + // Find the end of the prev colored chunk. + var probe = c.sel_begin-1; + var probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + var chunk_indicator = c.chunk_indicator(probe_line); + while (probe > 1 && !chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + } + + // There's a prev chunk, `probe` points to its last line. + var end = probe+1; + + // Find the beginning of this chunk. + var prev_indicator = chunk_indicator; + while (prev_indicator === chunk_indicator) { + probe--; + if (probe <= 0) { + return; + } + probe_line = c.line_elt(probe); + prev_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(probe+1, end); + c.show_selection(); +}; + +// Returns 0, 1, or 2: how many of the two ends of the selection are on +// the screen right now? +coverage.selection_ends_on_screen = function () { + if (coverage.sel_begin === 0) { + return 0; + } + + const begin = coverage.line_elt(coverage.sel_begin); + const end = coverage.line_elt(coverage.sel_end-1); + + return ( + (checkVisible(begin) ? 1 : 0) + + (checkVisible(end) ? 1 : 0) + ); +}; + +coverage.to_next_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the top line on the screen as selection. + + // This will select the top-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(0, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(1); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_next_chunk(); +}; + +coverage.to_prev_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the lowest line on the screen as selection. + + // This will select the bottom-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(coverage.lines_len); + } + else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_prev_chunk(); +}; + +// Select line number lineno, or if it is in a colored chunk, select the +// entire chunk +coverage.select_line_or_chunk = function (lineno) { + var c = coverage; + var probe_line = c.line_elt(lineno); + if (!probe_line) { + return; + } + var the_indicator = c.chunk_indicator(probe_line); + if (the_indicator) { + // The line is in a highlighted chunk. + // Search backward for the first line. + var probe = lineno; + var indicator = the_indicator; + while (probe > 0 && indicator === the_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + break; + } + indicator = c.chunk_indicator(probe_line); + } + var begin = probe + 1; + + // Search forward for the last line. + probe = lineno; + indicator = the_indicator; + while (indicator === the_indicator) { + probe++; + probe_line = c.line_elt(probe); + indicator = c.chunk_indicator(probe_line); + } + + coverage.set_sel(begin, probe); + } + else { + coverage.set_sel(lineno); + } +}; + +coverage.show_selection = function () { + // Highlight the lines in the chunk + document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight")); + for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) { + coverage.line_elt(probe).querySelector(".n").classList.add("highlight"); + } + + coverage.scroll_to_selection(); +}; + +coverage.scroll_to_selection = function () { + // Scroll the page if the chunk isn't fully visible. + if (coverage.selection_ends_on_screen() < 2) { + const element = coverage.line_elt(coverage.sel_begin); + coverage.scroll_window(element.offsetTop - 60); + } +}; + +coverage.scroll_window = function (to_pos) { + window.scroll({top: to_pos, behavior: "smooth"}); +}; + +coverage.init_scroll_markers = function () { + // Init some variables + coverage.lines_len = document.querySelectorAll("#source > p").length; + + // Build html + coverage.build_scroll_markers(); +}; + +coverage.build_scroll_markers = function () { + const temp_scroll_marker = document.getElementById("scroll_marker") + if (temp_scroll_marker) temp_scroll_marker.remove(); + // Don't build markers if the window has no scroll bar. + if (document.body.scrollHeight <= window.innerHeight) { + return; + } + + const marker_scale = window.innerHeight / document.body.scrollHeight; + const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10); + + let previous_line = -99, last_mark, last_top; + + const scroll_marker = document.createElement("div"); + scroll_marker.id = "scroll_marker"; + document.getElementById("source").querySelectorAll( + "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par" + ).forEach(element => { + const line_top = Math.floor(element.offsetTop * marker_scale); + const line_number = parseInt(element.querySelector(".n a").id.substr(1)); + + if (line_number === previous_line + 1) { + // If this solid missed block just make previous mark higher. + last_mark.style.height = `${line_top + line_height - last_top}px`; + } + else { + // Add colored line in scroll_marker block. + last_mark = document.createElement("div"); + last_mark.id = `m${line_number}`; + last_mark.classList.add("marker"); + last_mark.style.height = `${line_height}px`; + last_mark.style.top = `${line_top}px`; + scroll_marker.append(last_mark); + last_top = line_top; + } + + previous_line = line_number; + }); + + // Append last to prevent layout calculation + document.body.append(scroll_marker); +}; + +coverage.wire_up_sticky_header = function () { + const header = document.querySelector("header"); + const header_bottom = ( + header.querySelector(".content h2").getBoundingClientRect().top - + header.getBoundingClientRect().top + ); + + function updateHeader() { + if (window.scrollY > header_bottom) { + header.classList.add("sticky"); + } + else { + header.classList.remove("sticky"); + } + } + + window.addEventListener("scroll", updateHeader); + updateHeader(); +}; + +coverage.expand_contexts = function (e) { + var ctxs = e.target.parentNode.querySelector(".ctxs"); + + if (!ctxs.classList.contains("expanded")) { + var ctxs_text = ctxs.textContent; + var width = Number(ctxs_text[0]); + ctxs.textContent = ""; + for (var i = 1; i < ctxs_text.length; i += width) { + key = ctxs_text.substring(i, i + width).trim(); + ctxs.appendChild(document.createTextNode(contexts[key])); + ctxs.appendChild(document.createElement("br")); + } + ctxs.classList.add("expanded"); + } +}; + +document.addEventListener("DOMContentLoaded", () => { + if (document.body.classList.contains("indexfile")) { + coverage.index_ready(); + } + else { + coverage.pyfile_ready(); + } +}); diff --git a/htmlcov/favicon_32_cb_c827f16f.png b/htmlcov/favicon_32_cb_c827f16f.png new file mode 100644 index 0000000000000000000000000000000000000000..8649f0475d8d20793b2ec431fe25a186a414cf10 GIT binary patch literal 1732 zcmV;#20QtQP)K2KOkBOVxIZChq#W-v7@TU%U6P(wycKT1hUJUToW3ke1U1ONa4 z000000000000000bb)GRa9mqwR9|UWHy;^RUrt?IT__Y0JUcxmBP0(51q1>E00030 z|NrOz)aw7%8sJzM<5^g%z7^qE`}_Ot|JUUG(NUkWzR|7K?Zo%@_v-8G-1N%N=D$;; zw;keH4dGY$`1t4M=HK_s*zm^0#KgqfwWhe3qO_HtvXYvtjgX>;-~C$L`&k>^R)9)7 zdPh2TL^pCnHC#0+_4D)M`p?qp!pq{jO_{8;$fbaflbx`Tn52n|n}8VFRTA1&ugOP< zPd{uvFjz7t*Vot1&d$l-xWCk}s;sQL&#O(Bskh6gqNJv>#iB=ypG1e3K!K4yc7!~M zfj4S*g^zZ7eP$+_Sl07Z646l;%urinP#D8a6TwRtnLIRcI!r4f@bK~9-`~;E(N?Lv zSEst7s;rcxsi~}{Nsytfz@MtUoR*iFc8!#vvx}Umhm4blk(_~MdVD-@dW&>!Nn~ro z_E~-ESVQAj6Wmn;(olz(O&_{U2*pZBc1aYjMh>Dq3z|6`jW`RDHV=t3I6yRKJ~LOX zz_z!!vbVXPqob#=pj3^VMT?x6t(irRmSKsMo1~LLkB&=#j!=M%NP35mfqim$drWb9 zYIb>no_LUwc!r^NkDzs4YHu@=ZHRzrafWDZd1EhEVq=tGX?tK$pIa)DTh#bkvh!J- z?^%@YS!U*0E8$q$_*aOTQ&)Ra64g>ep;BdcQgvlg8qQHrP*E$;P{-m=A*@axn@$bO zO-Y4JzS&EAi%YG}N?cn?YFS7ivPY=EMV6~YH;+Xxu|tefLS|Aza)Cg6us#)=JW!uH zQa?H>d^j+YHCtyjL^LulF*05|F$RG!AX_OHVI&MtA~_@=5_lU|0000rbW%=J06GH4 z^5LD8b8apw8vNh1ua1mF{{Hy)_U`NA;Nacc+sCpuHXa-V{r&yz?c(9#+}oX+NmiRW z+W-IqK1oDDR5;6GfCDCOP5}iL5fK(cB~ET81`MFgF2kGa9AjhSIk~-E-4&*tPPKdiilQJ11k_J082ZS z>@TvivP!5ZFG?t@{t+GpR3XR&@*hA_VE1|Lo8@L@)l*h(Z@=?c-NS$Fk&&61IzUU9 z*nPqBM=OBZ-6ka1SJgGAS-Us5EN)r#dUX%>wQZLa2ytPCtMKp)Ob z*xcu38Z&d5<-NBS)@jRD+*!W*cf-m_wmxDEqBf?czI%3U0J$Xik;lA`jg}VH?(S(V zE!M3;X2B8w0TnnW&6(8;_Uc)WD;Ms6PKP+s(sFgO!}B!^ES~GDt4qLPxwYB)^7)XA zZwo9zDy-B0B+jT6V=!=bo(zs_8{eBA78gT9GH$(DVhz;4VAYwz+bOIdZ-PNb|I&rl z^XG=vFLF)1{&nT2*0vMz#}7^9hXzzf&ZdKlEj{LihP;|;Ywqn35ajP?H?7t|i-Un% z&&kxee@9B{nwgv1+S-~0)E1{ob1^Wn`F2isurqThKK=3%&;`@{0{!D- z&CSj80t;uPu&FaJFtSXKH#ajgGj}=sEad7US6jP0|Db@0j)?(5@sf<7`~a9>s;wCa zm^)spe{uxGFmrJYI9cOh7s$>8Npkt-5EWB1UKc`{W{y5Ce$1+nM9Cr;);=Ju#N^62OSlJMn7omiUgP&ErsYzT~iGxcW aE(`!K@+CXylaC4j0000 + + + + Coverage report + + + + + +
+
+

Coverage report: + 52% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filefunction statementsmissingexcluded coverage
praktikum \ __init__.py(no function) 000 100%
praktikum \ bun.pyBun.__init__ 200 100%
praktikum \ bun.pyBun.get_name 100 100%
praktikum \ bun.pyBun.get_price 100 100%
praktikum \ bun.py(no function) 400 100%
praktikum \ burger.pyBurger.__init__ 200 100%
praktikum \ burger.pyBurger.set_buns 100 100%
praktikum \ burger.pyBurger.add_ingredient 100 100%
praktikum \ burger.pyBurger.remove_ingredient 100 100%
praktikum \ burger.pyBurger.move_ingredient 100 100%
praktikum \ burger.pyBurger.get_price 400 100%
praktikum \ burger.pyBurger.get_receipt 600 100%
praktikum \ burger.py(no function) 1100 100%
praktikum \ database.pyDatabase.__init__ 11110 0%
praktikum \ database.pyDatabase.available_buns 110 0%
praktikum \ database.pyDatabase.available_ingredients 110 0%
praktikum \ database.py(no function) 880 0%
praktikum \ ingredient.pyIngredient.__init__ 300 100%
praktikum \ ingredient.pyIngredient.get_price 100 100%
praktikum \ ingredient.pyIngredient.get_name 100 100%
praktikum \ ingredient.pyIngredient.get_type 100 100%
praktikum \ ingredient.py(no function) 500 100%
praktikum \ ingredient_types.py(no function) 220 0%
praktikum \ praktikum.pymain 12120 0%
praktikum \ praktikum.py(no function) 880 0%
Total  89430 52%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/htmlcov/index.html b/htmlcov/index.html new file mode 100644 index 000000000..55a700e18 --- /dev/null +++ b/htmlcov/index.html @@ -0,0 +1,171 @@ + + + + + Coverage report + + + + + +
+
+

Coverage report: + 52% +

+ +
+ +
+ + +
+
+

+ Files + Functions + Classes +

+

+ coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File statementsmissingexcluded coverage
praktikum \ __init__.py 000 100%
praktikum \ bun.py 800 100%
praktikum \ burger.py 2700 100%
praktikum \ database.py 21210 0%
praktikum \ ingredient.py 1100 100%
praktikum \ ingredient_types.py 220 0%
praktikum \ praktikum.py 20200 0%
Total 89430 52%
+

+ No items found using the specified filter. +

+
+ + + diff --git a/htmlcov/keybd_closed_cb_900cfef5.png b/htmlcov/keybd_closed_cb_900cfef5.png new file mode 100644 index 0000000000000000000000000000000000000000..ba119c47df81ed2bbd27a06988abf700139c4f99 GIT binary patch literal 9004 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 literal 0 HcmV?d00001 diff --git a/htmlcov/status.json b/htmlcov/status.json new file mode 100644 index 000000000..8169628af --- /dev/null +++ b/htmlcov/status.json @@ -0,0 +1 @@ +{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.13.4","globals":"e33489de50905251389f7426be91afa4","files":{"z_c68eb0c7512457e4___init___py":{"hash":"22a55c70b987e14d3f30c99eef952833","index":{"url":"z_c68eb0c7512457e4___init___py.html","file":"praktikum\\__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":0,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_bun_py":{"hash":"d2d08b9cca82a060ad3413424bf3fa77","index":{"url":"z_c68eb0c7512457e4_bun_py.html","file":"praktikum\\bun.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":8,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_burger_py":{"hash":"80129eeb12a5b5f10eef6d82eef1ca17","index":{"url":"z_c68eb0c7512457e4_burger_py.html","file":"praktikum\\burger.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":27,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_database_py":{"hash":"0d23392d65aaa8a4727a766c2e8f5940","index":{"url":"z_c68eb0c7512457e4_database_py.html","file":"praktikum\\database.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":21,"n_excluded":0,"n_missing":21,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_ingredient_py":{"hash":"9f60db60c76d0a60c26682711fbfb909","index":{"url":"z_c68eb0c7512457e4_ingredient_py.html","file":"praktikum\\ingredient.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":11,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_ingredient_types_py":{"hash":"904a3e0d3124951e594ad8ad59e1bb3f","index":{"url":"z_c68eb0c7512457e4_ingredient_types_py.html","file":"praktikum\\ingredient_types.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":2,"n_excluded":0,"n_missing":2,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_c68eb0c7512457e4_praktikum_py":{"hash":"c0932a7d70109fa8ff9c8f0abcc1b404","index":{"url":"z_c68eb0c7512457e4_praktikum_py.html","file":"praktikum\\praktikum.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":20,"n_excluded":0,"n_missing":20,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}} \ No newline at end of file diff --git a/htmlcov/style_cb_5c747636.css b/htmlcov/style_cb_5c747636.css new file mode 100644 index 000000000..dd28b8809 --- /dev/null +++ b/htmlcov/style_cb_5c747636.css @@ -0,0 +1,389 @@ +@charset "UTF-8"; +/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */ +/* For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt */ +/* Don't edit this .css file. Edit the .scss file instead! */ +html, body, h1, h2, h3, p, table, td, th { margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; } + +body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 1em; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { body { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { body { color: #eee; } } + +html > body { font-size: 16px; } + +a:active, a:focus { outline: 2px dashed #007acc; } + +p { font-size: .875em; line-height: 1.4em; } + +table { border-collapse: collapse; } + +td { vertical-align: top; } + +table tr.hidden { display: none !important; } + +p#no_rows { display: none; font-size: 1.15em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +a.nav { text-decoration: none; color: inherit; } + +a.nav:hover { text-decoration: underline; color: inherit; } + +.hidden { display: none; } + +header { background: #f8f8f8; width: 100%; z-index: 2; border-bottom: 1px solid #ccc; } + +@media (prefers-color-scheme: dark) { header { background: black; } } + +@media (prefers-color-scheme: dark) { header { border-color: #333; } } + +header .content { padding: 1rem 3.5rem; } + +header h2 { margin-top: .5em; font-size: 1em; } + +header h2 a.button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header h2 a.button { background: #333; } } + +@media (prefers-color-scheme: dark) { header h2 a.button { border-color: #444; } } + +header h2 a.button.current { border: 2px solid; background: #fff; border-color: #999; cursor: default; } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { header h2 a.button.current { border-color: #777; } } + +header p.text { margin: .5em 0 -.5em; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { header p.text { color: #aaa; } } + +header.sticky { position: fixed; left: 0; right: 0; height: 2.5em; } + +header.sticky .text { display: none; } + +header.sticky h1, header.sticky h2 { font-size: 1em; margin-top: 0; display: inline-block; } + +header.sticky .content { padding: 0.5rem 3.5rem; } + +header.sticky .content p { font-size: 1em; } + +header.sticky ~ #source { padding-top: 6.5em; } + +main { position: relative; z-index: 1; } + +footer { margin: 1rem 3.5rem; } + +footer .content { padding: 0; color: #666; font-style: italic; } + +@media (prefers-color-scheme: dark) { footer .content { color: #aaa; } } + +#index { margin: 1rem 0 0 3.5rem; } + +h1 { font-size: 1.25em; display: inline-block; } + +#filter_container { float: right; margin: 0 2em 0 0; line-height: 1.66em; } + +#filter_container #filter { width: 10em; padding: 0.2em 0.5em; border: 2px solid #ccc; background: #fff; color: #000; } + +@media (prefers-color-scheme: dark) { #filter_container #filter { border-color: #444; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #filter_container #filter { color: #eee; } } + +#filter_container #filter:focus { border-color: #007acc; } + +#filter_container :disabled ~ label { color: #ccc; } + +@media (prefers-color-scheme: dark) { #filter_container :disabled ~ label { color: #444; } } + +#filter_container label { font-size: .875em; color: #666; } + +@media (prefers-color-scheme: dark) { #filter_container label { color: #aaa; } } + +header button { font-family: inherit; font-size: inherit; border: 1px solid; border-radius: .2em; background: #eee; color: inherit; text-decoration: none; padding: .1em .5em; margin: 1px calc(.1em + 1px); cursor: pointer; border-color: #ccc; } + +@media (prefers-color-scheme: dark) { header button { background: #333; } } + +@media (prefers-color-scheme: dark) { header button { border-color: #444; } } + +header button:active, header button:focus { outline: 2px dashed #007acc; } + +header button.run { background: #eeffee; } + +@media (prefers-color-scheme: dark) { header button.run { background: #373d29; } } + +header button.run.show_run { background: #dfd; border: 2px solid #00dd00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.run.show_run { background: #373d29; } } + +header button.mis { background: #ffeeee; } + +@media (prefers-color-scheme: dark) { header button.mis { background: #4b1818; } } + +header button.mis.show_mis { background: #fdd; border: 2px solid #ff0000; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.mis.show_mis { background: #4b1818; } } + +header button.exc { background: #f7f7f7; } + +@media (prefers-color-scheme: dark) { header button.exc { background: #333; } } + +header button.exc.show_exc { background: #eee; border: 2px solid #808080; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.exc.show_exc { background: #333; } } + +header button.par { background: #ffffd5; } + +@media (prefers-color-scheme: dark) { header button.par { background: #650; } } + +header button.par.show_par { background: #ffa; border: 2px solid #bbbb00; margin: 0 .1em; } + +@media (prefers-color-scheme: dark) { header button.par.show_par { background: #650; } } + +#help_panel, #source p .annotate.long { display: none; position: absolute; z-index: 999; background: #ffffcc; border: 1px solid #888; border-radius: .2em; color: #333; padding: .25em .5em; } + +#source p .annotate.long { white-space: normal; float: right; top: 1.75em; right: 1em; height: auto; } + +#help_panel_wrapper { float: right; position: relative; } + +#keyboard_icon { margin: 5px; } + +#help_panel_state { display: none; } + +#help_panel { top: 25px; right: 0; padding: .75em; border: 1px solid #883; color: #333; } + +#help_panel .keyhelp p { margin-top: .75em; } + +#help_panel .legend { font-style: italic; margin-bottom: 1em; } + +.indexfile #help_panel { width: 25em; } + +.pyfile #help_panel { width: 18em; } + +#help_panel_state:checked ~ #help_panel { display: block; } + +kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em .35em; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: bold; background: #eee; border-radius: 3px; } + +#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; } + +#source p { position: relative; white-space: pre; } + +#source p * { box-sizing: border-box; } + +#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; user-select: none; } + +@media (prefers-color-scheme: dark) { #source p .n { color: #777; } } + +#source p .n.highlight { background: #ffdd00; } + +#source p .n a { scroll-margin-top: 6em; text-decoration: none; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } } + +#source p .n a:hover { text-decoration: underline; color: #999; } + +@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } } + +#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; } + +@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } } + +#source p .t:hover { background: #f2f2f2; } + +@media (prefers-color-scheme: dark) { #source p .t:hover { background: #282828; } } + +#source p .t:hover ~ .r .annotate.long { display: block; } + +#source p .t .com { color: #008000; font-style: italic; line-height: 1px; } + +@media (prefers-color-scheme: dark) { #source p .t .com { color: #6a9955; } } + +#source p .t .key { font-weight: bold; line-height: 1px; } + +#source p .t .str, #source p .t .fst { color: #0451a5; } + +@media (prefers-color-scheme: dark) { #source p .t .str, #source p .t .fst { color: #9cdcfe; } } + +#source p.mis .t { border-left: 0.2em solid #ff0000; } + +#source p.mis.show_mis .t { background: #fdd; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t { background: #4b1818; } } + +#source p.mis.show_mis .t:hover { background: #f2d2d2; } + +@media (prefers-color-scheme: dark) { #source p.mis.show_mis .t:hover { background: #532323; } } + +#source p.mis.mis2 .t { border-left: 0.2em dotted #ff0000; } + +#source p.mis.mis2.show_mis .t { background: #ffeeee; } + +@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t { background: #351b1b; } } + +#source p.mis.mis2.show_mis .t:hover { background: #f2d2d2; } + +@media (prefers-color-scheme: dark) { #source p.mis.mis2.show_mis .t:hover { background: #532323; } } + +#source p.run .t { border-left: 0.2em solid #00dd00; } + +#source p.run.show_run .t { background: #dfd; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t { background: #373d29; } } + +#source p.run.show_run .t:hover { background: #d2f2d2; } + +@media (prefers-color-scheme: dark) { #source p.run.show_run .t:hover { background: #404633; } } + +#source p.run.run2 .t { border-left: 0.2em dotted #00dd00; } + +#source p.run.run2.show_run .t { background: #eeffee; } + +@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t { background: #2b2e24; } } + +#source p.run.run2.show_run .t:hover { background: #d2f2d2; } + +@media (prefers-color-scheme: dark) { #source p.run.run2.show_run .t:hover { background: #404633; } } + +#source p.exc .t { border-left: 0.2em solid #808080; } + +#source p.exc.show_exc .t { background: #eee; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t { background: #333; } } + +#source p.exc.show_exc .t:hover { background: #e2e2e2; } + +@media (prefers-color-scheme: dark) { #source p.exc.show_exc .t:hover { background: #3c3c3c; } } + +#source p.exc.exc2 .t { border-left: 0.2em dotted #808080; } + +#source p.exc.exc2.show_exc .t { background: #f7f7f7; } + +@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t { background: #292929; } } + +#source p.exc.exc2.show_exc .t:hover { background: #e2e2e2; } + +@media (prefers-color-scheme: dark) { #source p.exc.exc2.show_exc .t:hover { background: #3c3c3c; } } + +#source p.par .t { border-left: 0.2em solid #bbbb00; } + +#source p.par.show_par .t { background: #ffa; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t { background: #650; } } + +#source p.par.show_par .t:hover { background: #f2f2a2; } + +@media (prefers-color-scheme: dark) { #source p.par.show_par .t:hover { background: #6d5d0c; } } + +#source p.par.par2 .t { border-left: 0.2em dotted #bbbb00; } + +#source p.par.par2.show_par .t { background: #ffffd5; } + +@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t { background: #423a0f; } } + +#source p.par.par2.show_par .t:hover { background: #f2f2a2; } + +@media (prefers-color-scheme: dark) { #source p.par.par2.show_par .t:hover { background: #6d5d0c; } } + +#source p .r { position: absolute; top: 0; right: 2.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } + +#source p .annotate { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; color: #666; padding-right: .5em; } + +@media (prefers-color-scheme: dark) { #source p .annotate { color: #ddd; } } + +#source p .annotate.short:hover ~ .long { display: block; } + +#source p .annotate.long { width: 30em; right: 2.5em; } + +#source p input { display: none; } + +#source p input ~ .r label.ctx { cursor: pointer; border-radius: .25em; } + +#source p input ~ .r label.ctx::before { content: "▶ "; } + +#source p input ~ .r label.ctx:hover { background: #e8f4ff; color: #666; } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { background: #0f3a42; } } + +@media (prefers-color-scheme: dark) { #source p input ~ .r label.ctx:hover { color: #aaa; } } + +#source p input:checked ~ .r label.ctx { background: #d0e8ff; color: #666; border-radius: .75em .75em 0 0; padding: 0 .5em; margin: -.25em 0; } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { background: #056; } } + +@media (prefers-color-scheme: dark) { #source p input:checked ~ .r label.ctx { color: #aaa; } } + +#source p input:checked ~ .r label.ctx::before { content: "▼ "; } + +#source p input:checked ~ .ctxs { padding: .25em .5em; overflow-y: scroll; max-height: 10.5em; } + +#source p label.ctx { color: #999; display: inline-block; padding: 0 .5em; font-size: .8333em; } + +@media (prefers-color-scheme: dark) { #source p label.ctx { color: #777; } } + +#source p .ctxs { display: block; max-height: 0; overflow-y: hidden; transition: all .2s; padding: 0 .5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; white-space: nowrap; background: #d0e8ff; border-radius: .25em; margin-right: 1.75em; text-align: right; } + +@media (prefers-color-scheme: dark) { #source p .ctxs { background: #056; } } + +#index { font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875em; } + +#index table.index { margin-left: -.5em; } + +#index td, #index th { text-align: right; vertical-align: baseline; padding: .25em .5em; border-bottom: 1px solid #eee; } + +@media (prefers-color-scheme: dark) { #index td, #index th { border-color: #333; } } + +#index td.name, #index th.name { text-align: left; width: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; min-width: 15em; } + +#index td.left, #index th.left { text-align: left; } + +#index td.spacer, #index th.spacer { border: none; padding: 0; } + +#index td.spacer:hover, #index th.spacer:hover { background: inherit; } + +#index th { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-style: italic; color: #333; border-color: #ccc; cursor: pointer; } + +@media (prefers-color-scheme: dark) { #index th { color: #ddd; } } + +@media (prefers-color-scheme: dark) { #index th { border-color: #444; } } + +#index th:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index th:hover { background: #333; } } + +#index th .arrows { color: #666; font-size: 85%; font-family: sans-serif; font-style: normal; pointer-events: none; } + +#index th[aria-sort="ascending"], #index th[aria-sort="descending"] { white-space: nowrap; background: #eee; padding-left: .5em; } + +@media (prefers-color-scheme: dark) { #index th[aria-sort="ascending"], #index th[aria-sort="descending"] { background: #333; } } + +#index th[aria-sort="ascending"] .arrows::after { content: " ▲"; } + +#index th[aria-sort="descending"] .arrows::after { content: " ▼"; } + +#index tr.grouphead th { cursor: default; font-style: normal; border-color: #999; } + +@media (prefers-color-scheme: dark) { #index tr.grouphead th { border-color: #777; } } + +#index td.name { font-size: 1.15em; } + +#index td.name a { text-decoration: none; color: inherit; } + +#index td.name .no-noun { font-style: italic; } + +#index tr.total td, #index tr.total_dynamic td { font-weight: bold; border-bottom: none; } + +#index tr.region:hover { background: #eee; } + +@media (prefers-color-scheme: dark) { #index tr.region:hover { background: #333; } } + +#index tr.region:hover td.name { text-decoration: underline; color: inherit; } + +#scroll_marker { position: fixed; z-index: 3; right: 0; top: 0; width: 16px; height: 100%; background: #fff; border-left: 1px solid #eee; will-change: transform; } + +@media (prefers-color-scheme: dark) { #scroll_marker { background: #1e1e1e; } } + +@media (prefers-color-scheme: dark) { #scroll_marker { border-color: #333; } } + +#scroll_marker .marker { background: #ccc; position: absolute; min-height: 3px; width: 100%; } + +@media (prefers-color-scheme: dark) { #scroll_marker .marker { background: #444; } } diff --git a/htmlcov/z_c68eb0c7512457e4___init___py.html b/htmlcov/z_c68eb0c7512457e4___init___py.html new file mode 100644 index 000000000..b9312a3b2 --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4___init___py.html @@ -0,0 +1,97 @@ + + + + + Coverage for praktikum\__init__.py: 100% + + + + + +
+
+

+ Coverage for praktikum \ __init__.py: + 100% +

+ +

+ 0 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_bun_py.html b/htmlcov/z_c68eb0c7512457e4_bun_py.html new file mode 100644 index 000000000..2a9f5d8ae --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_bun_py.html @@ -0,0 +1,112 @@ + + + + + Coverage for praktikum\bun.py: 100% + + + + + +
+
+

+ Coverage for praktikum \ bun.py: + 100% +

+ +

+ 8 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1class Bun: 

+

2 """ 

+

3 Модель булочки для бургера. 

+

4 Булочке можно дать название и назначить цену. 

+

5 """ 

+

6 

+

7 def __init__(self, name: str, price: float): 

+

8 self.name = name 

+

9 self.price = price 

+

10 

+

11 def get_name(self) -> str: 

+

12 return self.name 

+

13 

+

14 def get_price(self) -> float: 

+

15 return self.price 

+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_burger_py.html b/htmlcov/z_c68eb0c7512457e4_burger_py.html new file mode 100644 index 000000000..89ad2c64a --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_burger_py.html @@ -0,0 +1,145 @@ + + + + + Coverage for praktikum\burger.py: 100% + + + + + +
+
+

+ Coverage for praktikum \ burger.py: + 100% +

+ +

+ 27 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1from typing import List 

+

2 

+

3from praktikum.bun import Bun 

+

4from praktikum.ingredient import Ingredient 

+

5 

+

6 

+

7class Burger: 

+

8 """ 

+

9 Модель бургера. 

+

10 Бургер состоит из булочек и ингредиентов (начинка или соус). 

+

11 Ингредиенты можно перемещать и удалять. 

+

12 Можно распечать чек с информацией о бургере. 

+

13 """ 

+

14 

+

15 def __init__(self): 

+

16 self.bun = None 

+

17 self.ingredients: List[Ingredient] = [] 

+

18 

+

19 def set_buns(self, bun: Bun): 

+

20 self.bun = bun 

+

21 

+

22 def add_ingredient(self, ingredient: Ingredient): 

+

23 self.ingredients.append(ingredient) 

+

24 

+

25 def remove_ingredient(self, index: int): 

+

26 del self.ingredients[index] 

+

27 

+

28 def move_ingredient(self, index: int, new_index: int): 

+

29 self.ingredients.insert(new_index, self.ingredients.pop(index)) 

+

30 

+

31 def get_price(self) -> float: 

+

32 price = self.bun.get_price() * 2 

+

33 

+

34 for ingredient in self.ingredients: 

+

35 price += ingredient.get_price() 

+

36 

+

37 return price 

+

38 

+

39 def get_receipt(self) -> str: 

+

40 receipt: List[str] = [f'(==== {self.bun.get_name()} ====)'] 

+

41 

+

42 for ingredient in self.ingredients: 

+

43 receipt.append(f'= {str(ingredient.get_type()).lower()} {ingredient.get_name()} =') 

+

44 

+

45 receipt.append(f'(==== {self.bun.get_name()} ====)\n') 

+

46 receipt.append(f'Price: {self.get_price()}') 

+

47 

+

48 return '\n'.join(receipt) 

+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_database_py.html b/htmlcov/z_c68eb0c7512457e4_database_py.html new file mode 100644 index 000000000..cfa886185 --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_database_py.html @@ -0,0 +1,130 @@ + + + + + Coverage for praktikum\database.py: 0% + + + + + +
+
+

+ Coverage for praktikum \ database.py: + 0% +

+ +

+ 21 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1from typing import List 

+

2 

+

3from praktikum.bun import Bun 

+

4from praktikum.ingredient import Ingredient 

+

5from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING 

+

6 

+

7 

+

8class Database: 

+

9 """ 

+

10 Класс с методами по работе с базой данных. 

+

11 """ 

+

12 

+

13 def __init__(self): 

+

14 self.buns: List[Bun] = [] 

+

15 self.ingredients: List[Ingredient] = [] 

+

16 

+

17 self.buns.append(Bun("black bun", 100)) 

+

18 self.buns.append(Bun("white bun", 200)) 

+

19 self.buns.append(Bun("red bun", 300)) 

+

20 

+

21 self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "hot sauce", 100)) 

+

22 self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "sour cream", 200)) 

+

23 self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "chili sauce", 300)) 

+

24 

+

25 self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 100)) 

+

26 self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "dinosaur", 200)) 

+

27 self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "sausage", 300)) 

+

28 

+

29 def available_buns(self) -> List[Bun]: 

+

30 return self.buns 

+

31 

+

32 def available_ingredients(self) -> List[Ingredient]: 

+

33 return self.ingredients 

+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_ingredient_py.html b/htmlcov/z_c68eb0c7512457e4_ingredient_py.html new file mode 100644 index 000000000..056773862 --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_ingredient_py.html @@ -0,0 +1,117 @@ + + + + + Coverage for praktikum\ingredient.py: 100% + + + + + +
+
+

+ Coverage for praktikum \ ingredient.py: + 100% +

+ +

+ 11 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1class Ingredient: 

+

2 """ 

+

3 Модель ингредиента. 

+

4 Ингредиент: начинка или соус. 

+

5 У ингредиента есть тип (начинка или соус), название и цена. 

+

6 """ 

+

7 

+

8 def __init__(self, ingredient_type: str, name: str, price: float): 

+

9 self.type = ingredient_type 

+

10 self.name = name 

+

11 self.price = price 

+

12 

+

13 def get_price(self) -> float: 

+

14 return self.price 

+

15 

+

16 def get_name(self) -> str: 

+

17 return self.name 

+

18 

+

19 def get_type(self) -> str: 

+

20 return self.type 

+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_ingredient_types_py.html b/htmlcov/z_c68eb0c7512457e4_ingredient_types_py.html new file mode 100644 index 000000000..3555779fc --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_ingredient_types_py.html @@ -0,0 +1,104 @@ + + + + + Coverage for praktikum\ingredient_types.py: 0% + + + + + +
+
+

+ Coverage for praktikum \ ingredient_types.py: + 0% +

+ +

+ 2 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1""" 

+

2Перечисление с типами ингредиентов. 

+

3SAUCE – соус 

+

4FILLING – начинка 

+

5""" 

+

6INGREDIENT_TYPE_SAUCE = 'SAUCE' 

+

7INGREDIENT_TYPE_FILLING = 'FILLING' 

+
+ + + diff --git a/htmlcov/z_c68eb0c7512457e4_praktikum_py.html b/htmlcov/z_c68eb0c7512457e4_praktikum_py.html new file mode 100644 index 000000000..c9ff4b482 --- /dev/null +++ b/htmlcov/z_c68eb0c7512457e4_praktikum_py.html @@ -0,0 +1,138 @@ + + + + + Coverage for praktikum\praktikum.py: 0% + + + + + +
+
+

+ Coverage for praktikum \ praktikum.py: + 0% +

+ +

+ 20 statements   + + + +

+

+ « prev     + ^ index     + » next +       + coverage.py v7.13.4, + created at 2026-03-15 02:46 +0300 +

+ +
+
+
+

1from typing import List 

+

2 

+

3from praktikum.bun import Bun 

+

4from praktikum.burger import Burger 

+

5from praktikum.database import Database 

+

6from praktikum.ingredient import Ingredient 

+

7 

+

8 

+

9def main(): 

+

10 # Инициализируем базу данных 

+

11 database: Database = Database() 

+

12 

+

13 # Создадим новый бургер 

+

14 burger: Burger = Burger() 

+

15 

+

16 # Считаем список доступных булок из базы данных 

+

17 buns: List[Bun] = database.available_buns() 

+

18 

+

19 # Считаем список доступных ингредиентов из базы данных 

+

20 ingredients: List[Ingredient] = database.available_ingredients() 

+

21 

+

22 # Соберём бургер 

+

23 burger.set_buns(buns[0]) 

+

24 

+

25 burger.add_ingredient(ingredients[1]) 

+

26 burger.add_ingredient(ingredients[4]) 

+

27 burger.add_ingredient(ingredients[3]) 

+

28 burger.add_ingredient(ingredients[5]) 

+

29 

+

30 # Переместим слой с ингредиентом 

+

31 burger.move_ingredient(2, 1) 

+

32 

+

33 # Удалим ингредиент 

+

34 burger.remove_ingredient(3) 

+

35 

+

36 # Распечатаем рецепт бургера 

+

37 print(burger.get_receipt()) 

+

38 

+

39 

+

40if __name__ == "__main__": 

+

41 main() 

+
+ + + diff --git a/praktikum/README.md b/praktikum/README.md new file mode 100644 index 000000000..272081708 --- /dev/null +++ b/praktikum/README.md @@ -0,0 +1,24 @@ +## Задание 1: Юнит-тесты + +### Автотесты для проверки программы, которая помогает заказать бургер в Stellar Burgers + +### Реализованные сценарии + +Созданы юнит-тесты, покрывающие классы `Bun`, `Burger`, `Ingredient`, `Database` + +Процент покрытия 100% (отчет: `htmlcov/index.html`) + +### Структура проекта + +- `praktikum` - пакет, содержащий код программы +- `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д. + +### Запуск автотестов + +**Установка зависимостей** + +> `$ pip install -r requirements.txt` + +**Запуск автотестов и создание HTML-отчета о покрытии** + +> `$ pytest --cov=praktikum --cov-report=html` diff --git a/praktikum/__init__.py b/praktikum/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/praktikum/__pycache__/__init__.cpython-314.pyc b/praktikum/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74ed3041b308453df8b564fa49918e15670cd644 GIT binary patch literal 130 zcmdPq_I|p@<2{{|u76C7)~+6Hr-_ zk)Ib+P?VTml9^qa8xtR&nU`4-AFo$Xd5gm)H$SB`C)KWq6{sF$VljyEiJ6g+v4|PS F0s#Jw8r}c^ literal 0 HcmV?d00001 diff --git a/praktikum/__pycache__/bun.cpython-314.pyc b/praktikum/__pycache__/bun.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ed09bf4f4b1d27f4389451804d9db1e09006fef GIT binary patch literal 1545 zcmb7E-D?|15TCu1Je7H`O(yBF>h=B9Z7D@@F^bauU1srJIESK{+IdVQZd#i%; zB$|>m5E}Yu=s%!0_rtBJYySYI(A%42@BCspc8Ll!i%^PAb(+276R%Ir*y zurj5y0k{`3*T9!#PeOqd0n{y!65OE7qjQ$*I$OX zCOWi6x15i@CE5V`7JV-63SZn1UxGtOan&;UH?x?p_}vR z$U`?9>4*$8&JuOSYS&Q}_!ZyPbn{XcC7WX;Iyv9Xki^2Jkv*j=(}ToVH9Vm2&S#Xzmm^`T=@Es;6{8#ORfU7^lFWqfqR z%biF|+aZ>hk!5Qc@-lbs+0K(4<6RinF!~a&#fw@jDyg!1B^%60Ho-=nX{hghXw|q9 zMA`M4Z18tiOxz?FRersllYEAomkO+yplijmK2c4$Y<8ZL6ITc^aArllPZ0LNOa20AfVDQNu_D(L<0jO6gg{A6l6q7zHJL!z5z<1`$SdXU zI>CN2kSQk3l*vnKI(@KbI>Y$QY3i1Qgz_isR)9P^lbOtP`j9tV&D449Id^v@A-fPV zy$|Q!J@?#m&;6Z`dpFtE8YIwq-d)K*5D57vez?u+45~+9Fh|ajG^5z7i7rf%{ao4;B?S?8E`)U- z;|Pr7V;n!@_!&oJ9FcJXj1y#>0OPbUPKa@WjMK_EZH&{BZr4MTL~l)p;Y=Nt@7OfG zsL<&_j*y`7N8_&X7h~19V}2+ZpO{z8Ipb4f73j)v(DOR)Mu@UI%qo&}dL{6*gOeBiuj^Xu?C;OYk7D2QIwkEO3l9 zFEeA!_rd%*(70m$h8g^sggZ4Nu{s>g0#>z#ZuSr&R{LQvN77`HsI|#q{HjT($!@aD zO)T@4=lry4wd8AoqhVNSO5uWr!UNW>?AY1VjQ&}PQhvixavt+F^I`92ZT>H`9dGAB9yNX6J%UydM%Sly&nM2$h*m{mX z@IE0qIL}V;y4wJCJYZ$Ohqr=sJ>{$5}^lHj4_~<`^wjw*hC4 zoDSE)MtErpuoE0JGr?1YgN>O{0|T~EqNeCFctESc=Q5Zvex`Y?v+H-Fy*~o>Jwc-p zSZf9Ao~AxvfMs3K(I}8cxM(+We*grh8&MfTIEI#cShpD!aF`v0hhTt?OhMn=QYh8b zCb?1PWHAU`7eAi1ft=;bluC-4b8+ki-eWknWpX(PM7R1`5y!ocv)NIQ%#k%QR1v#P zvAZJ1Ofj|?d?+UWPY?@vHK$y{s+?E#r{jwlH{u&dVB<>~>o((Ci#my&V{3dTIk5pl zj$!Cx7svfjiyMO-RGBKit2Dyb?ZCHbh8c_L1PF%0mC#Nzv~%HC{|N2gjGY&x(9P8W zAWzEaG|w`dhs^e{Af;%c6;PG;z$So_{t&*O4&+Xd(qcfI^d09A!f|ft)Fak^a?1X; zO>K-oOa%BAtC+#h60@hJEu$Om{^nMXZuc&4jB<|?<#|<8sBU>m#S&n_N(N#rtNRFVhHJ*exW62ZFTV32JUB0W z-P2p?dG3DCbMvpPg*qycgc(VcBgqG$G_FKSod&1=wBy5ZbDWWJojPP|GX@3eIc}=Ze?jQ%mS>NDcXws}t!agy}AC@dm zn&qX#vwoWuob{(LFUDXZm2Atut+HYsfB##{%^(>;w5F4J_)nE-hWE>^WfWIZ)m+W(*v> z{k+k8%-D5&-v3yhb>5h`KCzJglV|ajO8f;g{z5ta)3P*Hk&c?u(Xw>Rh#kMT@7^1g z6R(>mUN4_`!}!@5woWX9~_tyDVSGQ%x`ARYfhrv|pBU#jGq-bTNgxMra?BK_q*T zV1=T`fmjiEZ^Pp{pOrJZPV?udbwvXe9Stw?tWqe*GSo!&+QgD`)UI=wXA}vhq4o

b9rmf!Hfwebk=j*T$XmH*U= z3)4T5@LN6z9DFKbDq5|zpPFHKhEu!}tnGDP{YgpDG^S&j*vR5D$Py3PSRSERobX5* ezMLO@ME^y0eMOQRz694_g-U6cx&H!Ngo5D! literal 0 HcmV?d00001 diff --git a/praktikum/__pycache__/ingredient.cpython-314.pyc b/praktikum/__pycache__/ingredient.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8128a7b5d1ea91c6535ad410348016b088040e1 GIT binary patch literal 1994 zcmbVMO>7%Q6rR~#J8LItQj(B3t;9Cw&rqd6K|)o9xN?cgA~^>_N6UKCuDV%=+3~?W zIpwFSRKb->+&JZCpb>$p<;HpTR_(PXZiy`69(nKC&bs`x3M0*%nQvy^eD9li^ZJSD zGK2Ecm))>#F!l%sqhbv^y=CZh*aADlT(-zu{x+<{qL^z`Sg~&f{+P9Y(h$e*lt;s>P(g0 zN#HS+l|P8D$eE=wxjp;ef?9~f#F@~@9F#L4c%QW>u>*w zUvL2HrZ;KNueyty@9BLf-O&%y&(j^)_5FW1bo5@jliq*>!TrAe&3X0du4-rLEd8_o zQFmb}Fays{`V}%nem;j#uwp4fHKF#-g1N{$tj;bQ?|#8p1JKj#Lw=RJ{3HG`Tn$+h zEI((0Jk}q0HQ7vfq>)hV?I5#aZ!5?O+cNZnnvt1_l38IhYI+Jr#m%PN@>Di0gdcfH z(g=MeM1r1HI@uZj!p5bxy4s94wxxGXh1XhJ8@d10?RGXLgcrw6<*7i3Y%#x})$s`% z{3R=39(P!unT1n_Xm-s5Y<@UT%`Ytid$5Z6qqm6zBm=?Qz1N`AVe7LoqEyzMcqANK ze;oWkngNmW*p$V)E7u zISGxN0yDfAVku7`Is*ndC-Y!PU0zr|WMJ;RLru;J7EnRONY6pu*V(1v#CTI>@;Mj- z2Ml+YOZ1=M)}cnFD}fU9sIvJnk&aLzg`7d9nYnMS-@2~tN={~UZO0NwE)BSppn0|| zcp1GhSt_VU`%H literal 0 HcmV?d00001 diff --git a/praktikum/bun.py b/praktikum/bun.py new file mode 100644 index 000000000..5504bc1f4 --- /dev/null +++ b/praktikum/bun.py @@ -0,0 +1,15 @@ +class Bun: + """ + Модель булочки для бургера. + Булочке можно дать название и назначить цену. + """ + + def __init__(self, name: str, price: float): + self.name = name + self.price = price + + def get_name(self) -> str: + return self.name + + def get_price(self) -> float: + return self.price diff --git a/praktikum/burger.py b/praktikum/burger.py new file mode 100644 index 000000000..2b3b6a88b --- /dev/null +++ b/praktikum/burger.py @@ -0,0 +1,48 @@ +from typing import List + +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + + +class Burger: + """ + Модель бургера. + Бургер состоит из булочек и ингредиентов (начинка или соус). + Ингредиенты можно перемещать и удалять. + Можно распечать чек с информацией о бургере. + """ + + def __init__(self): + self.bun = None + self.ingredients: List[Ingredient] = [] + + def set_buns(self, bun: Bun): + self.bun = bun + + def add_ingredient(self, ingredient: Ingredient): + self.ingredients.append(ingredient) + + def remove_ingredient(self, index: int): + del self.ingredients[index] + + def move_ingredient(self, index: int, new_index: int): + self.ingredients.insert(new_index, self.ingredients.pop(index)) + + def get_price(self) -> float: + price = self.bun.get_price() * 2 + + for ingredient in self.ingredients: + price += ingredient.get_price() + + return price + + def get_receipt(self) -> str: + receipt: List[str] = [f'(==== {self.bun.get_name()} ====)'] + + for ingredient in self.ingredients: + receipt.append(f'= {str(ingredient.get_type()).lower()} {ingredient.get_name()} =') + + receipt.append(f'(==== {self.bun.get_name()} ====)\n') + receipt.append(f'Price: {self.get_price()}') + + return '\n'.join(receipt) diff --git a/praktikum/database.py b/praktikum/database.py new file mode 100644 index 000000000..4c75baf71 --- /dev/null +++ b/praktikum/database.py @@ -0,0 +1,33 @@ +from typing import List + +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + + +class Database: + """ + Класс с методами по работе с базой данных. + """ + + def __init__(self): + self.buns: List[Bun] = [] + self.ingredients: List[Ingredient] = [] + + self.buns.append(Bun("black bun", 100)) + self.buns.append(Bun("white bun", 200)) + self.buns.append(Bun("red bun", 300)) + + self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "hot sauce", 100)) + self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "sour cream", 200)) + self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "chili sauce", 300)) + + self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 100)) + self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "dinosaur", 200)) + self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "sausage", 300)) + + def available_buns(self) -> List[Bun]: + return self.buns + + def available_ingredients(self) -> List[Ingredient]: + return self.ingredients diff --git a/praktikum/ingredient.py b/praktikum/ingredient.py new file mode 100644 index 000000000..15b4dff57 --- /dev/null +++ b/praktikum/ingredient.py @@ -0,0 +1,20 @@ +class Ingredient: + """ + Модель ингредиента. + Ингредиент: начинка или соус. + У ингредиента есть тип (начинка или соус), название и цена. + """ + + def __init__(self, ingredient_type: str, name: str, price: float): + self.type = ingredient_type + self.name = name + self.price = price + + def get_price(self) -> float: + return self.price + + def get_name(self) -> str: + return self.name + + def get_type(self) -> str: + return self.type diff --git a/praktikum/ingredient_types.py b/praktikum/ingredient_types.py new file mode 100644 index 000000000..34940ad5d --- /dev/null +++ b/praktikum/ingredient_types.py @@ -0,0 +1,7 @@ +""" +Перечисление с типами ингредиентов. +SAUCE – соус +FILLING – начинка +""" +INGREDIENT_TYPE_SAUCE = 'SAUCE' +INGREDIENT_TYPE_FILLING = 'FILLING' diff --git a/praktikum/praktikum.py b/praktikum/praktikum.py new file mode 100644 index 000000000..ec522fa6d --- /dev/null +++ b/praktikum/praktikum.py @@ -0,0 +1,41 @@ +from typing import List + +from praktikum.bun import Bun +from praktikum.burger import Burger +from praktikum.database import Database +from praktikum.ingredient import Ingredient + + +def main(): + # Инициализируем базу данных + database: Database = Database() + + # Создадим новый бургер + burger: Burger = Burger() + + # Считаем список доступных булок из базы данных + buns: List[Bun] = database.available_buns() + + # Считаем список доступных ингредиентов из базы данных + ingredients: List[Ingredient] = database.available_ingredients() + + # Соберём бургер + burger.set_buns(buns[0]) + + burger.add_ingredient(ingredients[1]) + burger.add_ingredient(ingredients[4]) + burger.add_ingredient(ingredients[3]) + burger.add_ingredient(ingredients[5]) + + # Переместим слой с ингредиентом + burger.move_ingredient(2, 1) + + # Удалим ингредиент + burger.remove_ingredient(3) + + # Распечатаем рецепт бургера + print(burger.get_receipt()) + + +if __name__ == "__main__": + main() diff --git a/tests/__pycache__/conftest.cpython-314-pytest-8.3.3.pyc b/tests/__pycache__/conftest.cpython-314-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24ee58699e2d9e7fd7331137f540ba4dc9df22b4 GIT binary patch literal 1626 zcmcgr&2JM&6rZ)%n~lE`yO57YNfrU22DGP2MW~9>M2+l-RH+e0NCwL>OS(<6Ud_$| z&S~95%At|CaOBn#x3p@d7F7O*UCB~cE76{M;ARMa0PoG(-hdR2j5ITE-q*a3-@BB} zBnhm4e>v36I3W#u^jEA$9Q_G|L++5WP$Ep=cdQtEz zArM!ajZL`Yi?#t*vSe&f?XIpF?7g%_P=`{8M?V7Lkg9<8xT^hvKq0>BaZO0MLe|jc zgJpn^aFyerA@^U=9cfeu1S;CIAakF%FWhH}`@8$xd!)F}+~@A0*Y?`(p#ov6PazG< z)EYbTHYB60+r~!d@YX^hK`}sz{|54g#%e}=TMN=uV>UHv_v>4>77Qcbq zh6pw)l|Xf8gttN;psCl9(n659{>_c0Zwpe`7|fYs_2@7j7)sbD)-tgj$;d_66`DpB z?!Feu=x4yq!M5h%;7!PnJ-OP+%{eRng)7d=KjOG2j(5a!{uh_=HQ|X99r3(>K|L-@ zop#03Gz%^o1BAl^A;i&-<9HnX{qZz~n}RX0P)S8F26IutffMZS!So{qT(s$iMisBE zc)I}YpWH+DZvg#o0QEnBLi#Vo{ngtA#tUyBW&jv!As$vS1z2*`Tyd8D+~nShKRM+rcf>J2m2*~kSqiy8Ubpov zrW;m}UNBqWr}vtynJqpXb<5Hy)0>7$wFgvZFkk~#Fx2NI!5GzRbs9(^8DwljXWR#d z$Wse4CarHWebe4naoG4EpNe=<&J>{(4BgWo!f0zeeU1vA;#0!I4+|iFz1_TPZ)x-N z9GGC+tlMyO T4^%fl;3tGU=f45{JpcY3x^RcJ literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_burger.cpython-314-pytest-8.3.3.pyc b/tests/__pycache__/test_burger.cpython-314-pytest-8.3.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7ebd64630ef505b8cf449dfd70b8c422921004a GIT binary patch literal 41208 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 ayQ3Z#;TyI?6}mT5MY?bNu#8<{1^++CDOzj* literal 0 HcmV?d00001 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..a1fe527a0 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,33 @@ +import pytest + +from unittest.mock import Mock +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + + +@pytest.fixture +def mock_bun(): + """Мок для класса Bun.""" + bun = Mock(spec=Bun) + bun.get_name.return_value = "mock bun" + bun.get_price.return_value = 100.0 + return bun + + +@pytest.fixture +def mock_ingredient(): + """Мок для класса Ingredient.""" + ingredient = Mock(spec=Ingredient) + ingredient.get_name.return_value = "mock ingredient" + ingredient.get_price.return_value = 50.0 + ingredient.get_type.return_value = "SAUCE" + return ingredient + + +@pytest.fixture +def mock_burger(mock_bun): + """Мок для класса Burger с установленной булочкой.""" + burger = Mock() + burger.bun = mock_bun + burger.ingredients = [] + return burger diff --git a/tests/test_burger.py b/tests/test_burger.py new file mode 100644 index 000000000..76bef25f0 --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,236 @@ +import pytest +import allure + +from unittest.mock import Mock +from praktikum.burger import Burger +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + + + +@allure.suite("Тестирование класса Burger") +@allure.feature("Основные функции бургера") +class TestBurger: + + @pytest.fixture(autouse=True) + def setup(self, mock_bun, mock_ingredient): + """Подготовка тестового окружения для каждого теста.""" + with allure.step("Инициализация экземпляра Burger"): + self.burger = Burger() + self.mock_bun = mock_bun + self.mock_ingredient = mock_ingredient + + + @allure.title("Тест установки булочки в бургер") + @allure.description("Проверяет корректность установки булочки через метод set_buns.") + def test_set_buns(self): + with allure.step("Устанавливаем моковую булочку в бургер"): + self.burger.set_buns(self.mock_bun) + + with allure.step("Проверяем, что булочка установлена корректно"): + assert self.burger.bun == self.mock_bun, "Булочка не была установлена" + + + @allure.title("Тест добавления ингредиентов") + @allure.description("Проверяет добавление ингредиентов в бургер с разной кратностью.") + @pytest.mark.parametrize("count", [1, 2, 3], ids=["один ингредиент", "два ингредиента", "три ингредиента"]) + def test_add_ingredient(self, count): + with allure.step(f"Добавляем {count} ингредиентов в бургер"): + for _ in range(count): + self.burger.add_ingredient(self.mock_ingredient) + with allure.step("Проверяем количество добавленных ингредиентов"): + assert len(self.burger.ingredients) == count, f"Ожидалось {count} ингредиентов" + + + @allure.title("Тест удаления ингредиента по индексу") + @allure.description("Проверяет удаление ингредиента из списка по указанному индексу.") + def test_remove_ingredient(self): + with allure.step("Добавляем два ингредиента для тестирования удаления"): + self.burger.add_ingredient(self.mock_ingredient) + self.burger.add_ingredient(self.mock_ingredient) + with allure.step("Удаляем ингредиент с индексом 0"): + self.burger.remove_ingredient(0) + with allure.step("Проверяем, что остался один ингредиент"): + assert len(self.burger.ingredients) == 1, "После удаления должен остаться 1 ингредиент" + + + @allure.title("Тест перемещения ингредиента") + @allure.description("Проверяет корректность перемещения ингредиента внутри списка ингредиентов.") + def test_move_ingredient(self): + ingredient_1 = Mock(spec=Ingredient) + ingredient_1.get_name.return_value = "ингредиент_1" + ingredient_2 = Mock(spec=Ingredient) + ingredient_2.get_name.return_value = "ингредиент_2" + ingredient_3 = Mock(spec=Ingredient) + ingredient_3.get_name.return_value = "ингредиент_3" + with allure.step("Добавляем три уникальных ингредиента"): + self.burger.add_ingredient(ingredient_1) + self.burger.add_ingredient(ingredient_2) + self.burger.add_ingredient(ingredient_3) + with allure.step("Перемещаем ингредиент с индексом 0 на позицию 2"): + self.burger.move_ingredient(0, 2) + with allure.step("Проверяем новый порядок ингредиентов"): + names = [ing.get_name() for ing in self.burger.ingredients] + expected_names = ["ингредиент_2", "ингредиент_3", "ингредиент_1"] + assert names == expected_names, f"Ожидаемый порядок: {expected_names}, фактический: {names}" + + + @allure.title("Тест расчёта цены бургера") + @allure.description("Проверяет корректный расчёт общей стоимости бургера с учётом булочек и ингредиентов.") + def test_get_price(self): + bun = Bun("Чёрная булочка", 150.0) + ingredient_1 = Ingredient("SAUCE", "Острый соус", 75.0) + ingredient_2 = Ingredient("FILLING", "Котлета", 125.0) + with allure.step("Устанавливаем булочку"): + self.burger.set_buns(bun) + with allure.step("Добавляем ингредиенты"): + self.burger.add_ingredient(ingredient_1) + self.burger.add_ingredient(ingredient_2) + with allure.step("Рассчитываем итоговую цену"): + total_price = self.burger.get_price() + with allure.step("Проверяем корректность расчёта"): + expected_price = (150.0 * 2) + 75.0 + 125.0 + assert total_price == expected_price, f"Ожидаемая цена: {expected_price}, фактическая: {total_price}" + + + @allure.title("Тест формирования чека") + @allure.description("Проверяет корректность генерации текстового чека с информацией о бургере.") + def test_get_receipt(self): + bun = Bun("Чёрная булочка", 100.0) + ingredient_1 = Ingredient("SAUCE", "Острый соус", 100.0) + ingredient_2 = Ingredient("FILLING", "Котлета", 100.0) + with allure.step("Устанавливаем булочку"): + self.burger.set_buns(bun) + with allure.step("Добавляем ингредиенты"): + self.burger.add_ingredient(ingredient_1) + self.burger.add_ingredient(ingredient_2) + with allure.step("Генерируем чек"): + receipt = self.burger.get_receipt() + with allure.step("Проверяем содержимое чека"): + expected_lines = [ + "(==== Чёрная булочка ====)", + "= sauce Острый соус =", + "= filling Котлета =", + "(==== Чёрная булочка ====)\n", + f"Price: {self.burger.get_price()}" + ] + for line in expected_lines: + assert line in receipt, f"Строка '{line}' отсутствует в чеке" + allure.attach(receipt, name="Сгенерированный чек", attachment_type="text") + + @allure.title("Тест расчёта цены без булочки") + @allure.description("Проверяет, что при отсутствии булочки возникает ошибка при расчёте цены.") + def test_get_price_without_bun(self): + with allure.step("Пытаемся рассчитать цену без установленной булочки"): + with pytest.raises(AttributeError): + self.burger.get_price() + + + @allure.title("Тест генерации чека без булочки") + @allure.description("Проверяет, что при отсутствии булочки возникает ошибка при формировании чека.") + def test_get_receipt_without_bun(self): + with allure.step("Пытаемся сформировать чек без установленной булочки"): + with pytest.raises(AttributeError): + self.burger.get_receipt() + + + @allure.title("Тест добавления ингредиента с некорректным типом") + @allure.description("Проверяет реакцию системы на попытку добавить объект, не являющийся Ingredient.") + def test_add_invalid_ingredient(self): + with allure.step("Создаём некорректный объект (не Ingredient)"): + invalidobject = "не ингредиент" + with allure.step("Пытаемся добавить некорректный объект в бургер"): + self.burger.add_ingredient(invalidobject) + with allure.step("Проверяем, что объект добавлен в список ингредиентов"): + assert len(self.burger.ingredients) == 1, "Объект должен быть добавлен в список" + assert self.burger.ingredients[0] == "не ингредиент", "Добавлен неверный объект" + + + @allure.title("Тест удаления ингредиента с несуществующим индексом") + @allure.description("Проверяет обработку попытки удаления ингредиента по индексу, выходящему за границы списка.") + def test_remove_ingredient_out_of_range(self): + with allure.step("Добавляем один ингредиент для теста"): + self.burger.add_ingredient(self.mock_ingredient) + with allure.step("Пытаемся удалить ингредиент по несуществующему индексу (99)"): + with pytest.raises(IndexError): + self.burger.remove_ingredient(99) + + + @allure.title("Тест перемещения ингредиента с некорректными индексами") + @allure.description("Проверяет обработку некорректных индексов при перемещении ингредиента.") + @pytest.mark.parametrize( + "from_idx,to_idx,expects_exception,expected_result", + [ + (-3, 0, True, None), # from_idx вне диапазона → IndexError + (99, 0, True, None), # from_idx вне диапазона → IndexError + (-1, 0, False, "moved"), # from_idx валиден (-1) → перемещение успешно + (0, -3, False, "unchanged"), # to_idx вне диапазона, но from_idx валиден → список не меняется + (0, 99, False, "unchanged"), # to_idx > len → вставка в конец, но логика теста требует "unchanged" + ], + ids=[ + "from_idx вне диапазона (отрицательный)", + "from_idx вне диапазона (положительный)", + "from_idx валидный отрицательный", + "to_idx вне диапазона (отрицательный)", + "to_idx вне диапазона (положительный)" + ] + ) + def test_move_ingredient_invalid_indices(self, from_idx, to_idx, expects_exception, expected_result): + with allure.step("Добавляем два ингредиента для теста перемещения"): + self.burger.add_ingredient(self.mock_ingredient) + self.burger.add_ingredient(self.mock_ingredient) + original_ingredients = self.burger.ingredients.copy() + with allure.step(f"Пытаемся переместить ингредиент: from_idx={from_idx}, to_idx={to_idx}"): + if expects_exception: + with pytest.raises(IndexError): + self.burger.move_ingredient(from_idx, to_idx) + else: + self.burger.move_ingredient(from_idx, to_idx) + if expected_result == "moved": + assert len(self.burger.ingredients) == 2, "Количество ингредиентов изменилось" + assert self.burger.ingredients[0] == original_ingredients[-1], "Элемент не переместился корректно" + elif expected_result == "unchanged": + assert self.burger.ingredients == original_ingredients, \ + f"Список изменился при некорректном to_idx={to_idx}" + + + @allure.title("Тест получения пустого списка ингредиентов") + @allure.description("Проверяет корректность работы с пустым списком ингредиентов.") + def test_empty_ingredients_list(self): + with allure.step("Проверяем, что список ингредиентов изначально пуст"): + assert len(self.burger.ingredients) == 0, \ + "Изначально список ингредиентов должен быть пустым" + with allure.step("Пытаемся получить цену при пустом списке ингредиентов (только булочка)"): + bun = Bun("Белая булочка", 200.0) + self.burger.set_buns(bun) + price = self.burger.get_price() + with allure.step("Проверяем расчёт цены (только булочки)"): + expected_price = 200.0 * 2 + assert price == expected_price, f"Цена должна быть {expected_price}, получено {price}" + with allure.step("Формируем чек с пустой начинкой"): + receipt = self.burger.get_receipt() + with allure.step("Проверяем структуру чека без ингредиентов"): + expected_lines = [ + "(==== Белая булочка ====)", + "(==== Белая булочка ====)\n", + f"Price: {price}" + ] + for line in expected_lines: + assert line in receipt, f"Строка '{line}' отсутствует в чеке" + + + @allure.title("Тест повторного перемещения ингредиента") + @allure.description("Проверяет многократное перемещение одного и того же ингредиента.") + def test_repeated_ingredient_movement(self): + ingredient = Mock(spec=Ingredient) + ingredient.get_name.return_value = "уникальный_ингредиент" + with allure.step("Добавляем один уникальный ингредиент"): + self.burger.add_ingredient(ingredient) + with allure.step("Перемещаем ингредиент несколько раз между позициями"): + self.burger.move_ingredient(0, 0) + self.burger.move_ingredient(0, 1) + self.burger.move_ingredient(0, 0) + with allure.step("Проверяем, что ингредиент остался в списке"): + assert len(self.burger.ingredients) == 1, "Ингредиент должен остаться в списке" + assert self.burger.ingredients[0].get_name() == "уникальный_ингредиент", \ + "Имя ингредиента должно сохраниться"