context("Data transformation functions") test_that("yt_to_dataframe handles parse_dates=FALSE correctly", { mock_response <- mock_api_response( rows = list( c("2023-01-01", "100"), c("2023-01-02", "200") ), column_headers = list( list(name = "day", dataType = "STRING"), list(name = "views", dataType = "INTEGER") ), query = list( startDate = "2023-01-01", endDate = "2023-01-02", metrics = "views", dimensions = "day" ) ) df_with_dates <- yt_to_dataframe(mock_response, parse_dates = TRUE) expect_s3_class(df_with_dates$day, "Date") df_without_dates <- yt_to_dataframe(mock_response, parse_dates = FALSE) expect_type(df_without_dates$day, "character") }) test_that("yt_to_dataframe handles clean_names correctly", { mock_response <- mock_api_response( rows = list(c("123.45")), column_headers = list( list(name = "averageViewDuration", dataType = "FLOAT") ), query = list() ) df_clean <- yt_to_dataframe(mock_response, clean_names = TRUE) expect_true("average_view_duration" %in% names(df_clean)) df_original <- yt_to_dataframe(mock_response, clean_names = FALSE) expect_true("averageViewDuration" %in% names(df_original)) }) test_that("yt_to_dataframe returns NULL for invalid input", { expect_warning(result <- yt_to_dataframe(NULL)) expect_null(result) expect_warning(result <- yt_to_dataframe("not a list")) expect_null(result) }) test_that("yt_to_dataframe returns empty data.frame for empty rows", { mock_response <- list( columnHeaders = list(list(name = "views", dataType = "INTEGER")), rows = list() ) expect_message(result <- yt_to_dataframe(mock_response)) expect_true(is.data.frame(result)) expect_equal(nrow(result), 0) }) test_that("yt_extract_summary returns correct structure", { mock_response <- mock_api_response() summary <- yt_extract_summary(mock_response) expect_type(summary, "list") expect_equal(summary$total_rows, 2) expect_equal(summary$columns, 2) }) test_that("yt_extract_summary handles empty response", { mock_response <- list(rows = NULL) summary <- yt_extract_summary(mock_response) expect_equal(summary$total_rows, 0) }) test_that("yt_export_csv errors on empty data", { mock_response <- list( columnHeaders = list(list(name = "views", dataType = "INTEGER")), rows = list() ) expect_error( yt_export_csv(mock_response), class = "tubern_parameter_error" ) }) test_that("yt_quick_plot errors on empty data", { mock_response <- list( columnHeaders = list(list(name = "views", dataType = "INTEGER")), rows = list() ) expect_error( yt_quick_plot(mock_response), class = "tubern_parameter_error" ) }) test_that(".clean_column_names converts camelCase to snake_case", { result <- tubern:::.clean_column_names("averageViewDuration") expect_equal(result, "average_view_duration") result <- tubern:::.clean_column_names("estimatedMinutesWatched") expect_equal(result, "estimated_minutes_watched") }) test_that(".parse_column_types handles INTEGER type", { df <- data.frame(views = "100", stringsAsFactors = FALSE) headers <- list(list(name = "views", dataType = "INTEGER")) result <- tubern:::.parse_column_types(df, headers, parse_dates = FALSE) expect_type(result$views, "double") expect_equal(result$views, 100) }) test_that(".parse_column_types handles FLOAT type", { df <- data.frame(rate = "0.5", stringsAsFactors = FALSE) headers <- list(list(name = "rate", dataType = "FLOAT")) result <- tubern:::.parse_column_types(df, headers, parse_dates = FALSE) expect_type(result$rate, "double") expect_equal(result$rate, 0.5) })