root/src/tests/add-ons/kernel/file_systems/bfs/bfs_attribute_iterator_test.cpp
/*
 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
 * This file may be used under the terms of the MIT License.
 */


#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include <Entry.h>
#include <File.h>
#include <fs_attr.h>
#include <TypeConstants.h>


const char* kTempFile = "/tmp/bfs_attribute_iterator_test";

bool gVerbose;


bool
is_marker(const char* name)
{
        return strstr(name, ":marker") != NULL;
}


int32
attribute_index(const char* name)
{
        int32 number;
        if (sscanf(name, "test:%ld", &number) == 1)
                return number;

        return 0;
}


void
add_attributes(BFile& file, int32 start, int32 count)
{
        for (int32 index = start; index < start + count; index++) {
                char name[B_ATTR_NAME_LENGTH];
                snprintf(name, sizeof(name), "test:%ld", index);
                file.WriteAttr(name, B_INT32_TYPE, 0, &index, sizeof(int32));
        }
}


void
remove_attributes(BFile& file, int32 start, int32 count)
{
        for (int32 index = start; index < start + count; index++) {
                char name[B_ATTR_NAME_LENGTH];
                snprintf(name, sizeof(name), "test:%ld", index);
                file.RemoveAttr(name);
        }
}


void
add_marker_attribute(BFile& file, int32 index)
{
        char name[B_ATTR_NAME_LENGTH];
        snprintf(name, sizeof(name), "test:%ld:marker", index);
        file.WriteAttr(name, B_INT32_TYPE, 0, &index, sizeof(int32));
}


void
remove_marker_attribute(BFile& file, int32 index)
{
        char name[B_ATTR_NAME_LENGTH];
        snprintf(name, sizeof(name), "test:%ld:marker", index);
        file.RemoveAttr(name);
}


void
test_remove_attributes(BFile& file, int32 start, int32 count, int32 removeAt,
        int32 removeIndex1, int32 removeIndex2)
{
        int fd = file.Dup();
        if (fd < 0)
                return;

        int32 index = 0;
        bool seen[4096] = {0};

        if (gVerbose)
                printf("test removeAt %ld\n", removeAt);

        DIR* dir = fs_fopen_attr_dir(fd);
        while (struct dirent* entry = fs_read_attr_dir(dir)) {
                if (gVerbose)
                        printf("  %ld. %s\n", index, entry->d_name);
                if (index == removeAt) {
                        if (removeIndex1 > 0)
                                remove_marker_attribute(file, removeIndex1);
                        if (removeIndex2 > 0)
                                remove_marker_attribute(file, removeIndex2);
                }
                index++;

                if (is_marker(entry->d_name))
                        continue;

                int32 attributeIndex = attribute_index(entry->d_name);
                if (attributeIndex > 0) {
                        if (seen[attributeIndex]) {
                                printf("attribute index %ld already listed!\n", attributeIndex);
                                exit(1);
                        } else
                                seen[attributeIndex] = true;
                }
        }

        fs_close_attr_dir(dir);
        close(fd);

        for (int32 i = start; i < start + count; i++) {
                if (!seen[i]) {
                        printf("attribute index %ld not listed, saw only %ld/%ld!\n", i,
                                index, count);
                        exit(1);
                }
        }
}


void
test_add_attributes(BFile& file, int32 start, int32 count, int32 addAt,
        int32 addIndex1, int32 addIndex2)
{
        int fd = file.Dup();
        if (fd < 0)
                return;

        int32 index = 0;
        bool seen[4096] = {0};

        if (gVerbose)
                printf("test addAt %ld\n", addAt);

        DIR* dir = fs_fopen_attr_dir(fd);
        while (struct dirent* entry = fs_read_attr_dir(dir)) {
                if (gVerbose)
                        printf("  %ld. %s\n", index, entry->d_name);
                if (index == addAt) {
                        if (addIndex1 > 0)
                                add_marker_attribute(file, addIndex1);
                        if (addIndex2 > 0)
                                add_marker_attribute(file, addIndex2);
                }
                index++;

                if (is_marker(entry->d_name))
                        continue;

                int32 attributeIndex = attribute_index(entry->d_name);
                if (attributeIndex > 0) {
                        if (seen[attributeIndex]) {
                                printf("attribute index %ld already listed!\n", attributeIndex);
                                exit(1);
                        } else
                                seen[attributeIndex] = true;
                }
        }

        fs_close_attr_dir(dir);
        close(fd);

        for (int32 i = start; i < start + count; i++) {
                if (!seen[i]) {
                        printf("attribute index %ld not listed, saw only %ld/%ld!\n", i,
                                index, count);
                        exit(1);
                }
        }
}


int
main(int argc, char** argv)
{
        if (argc > 1 && !strcmp(argv[1], "-v"))
                gVerbose = true;

        BFile file;
        status_t status = file.SetTo(kTempFile, B_CREATE_FILE | B_READ_WRITE);
        if (status != B_OK) {
                fprintf(stderr, "Could not create temporary file: %s\n",
                        strerror(status));
                return 1;
        }

        puts("--------- Remove Tests ----------");

        // remove test, many attributes

        puts("Test 1...");

        for (int32 count = 5; count <= 100; count += 5) {
                add_attributes(file, 1, count);
                add_marker_attribute(file, count);
                add_attributes(file, count + 1, count);

                test_remove_attributes(file, 1, count,
                        count & 1 ? count - 1 : count + 1, count, -1);

                remove_attributes(file, 1, count * 2);
        }

        // remove test, all positions

        puts("Test 2...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 50);
                add_marker_attribute(file, 51);
                add_attributes(file, 51, 50);

                test_remove_attributes(file, 1, 100, i, 51, -1);

                remove_attributes(file, 1, 100);
        }

        // remove test, all positions, remove many

        puts("Test 3...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 33);
                add_marker_attribute(file, 33);
                add_attributes(file, 34, 34);
                add_marker_attribute(file, 67);
                add_attributes(file, 68, 33);

                test_remove_attributes(file, 1, 100, i, 33, 67);

                remove_attributes(file, 1, 100);
        }

        puts("--------- Add Tests ----------");

        // add test, many attributes

        puts("Test 4...");

        for (int32 count = 10; count <= 200; count += 10) {
                add_attributes(file, 1, count);

                int32 half = count / 2;

                test_add_attributes(file, 1, count,
                        half & 1 ? half - 1 : half + 1, half - 2, half + 2);

                remove_attributes(file, 1, count);
        }

        // add test, all iterator positions

        puts("Test 5...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 100);

                test_add_attributes(file, 1, 100, i, 50, -1);

                remove_attributes(file, 1, 100);
        }

        // add test, all attribute positions

        puts("Test 6...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 100);

                test_add_attributes(file, 1, 100, 50, i, -1);

                remove_attributes(file, 1, 100);
        }

        // add test, many attributes

        puts("Test 7...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 100);

                test_add_attributes(file, 1, 100, i, 33, 67);

                remove_attributes(file, 1, 100);
        }

        // add test, many attributes

        puts("Test 8...");

        for (int32 i = 1; i < 100; i++) {
                add_attributes(file, 1, 100);

                test_add_attributes(file, 1, 100, 50, i - 1, i + 1);

                remove_attributes(file, 1, 100);
        }

        BEntry entry;
        if (entry.SetTo(kTempFile) == B_OK)
                entry.Remove();

        return 0;
}